`
mooncui
  • 浏览: 71229 次
社区版块
存档分类
最新评论

关于Java中String的Memory问题

    博客分类:
  • Java
阅读更多

昨天看到一个blog,用一个极端例子来说明Java中的内存问题:

http://blog.xebia.com/2007/10/04/leaking-memory-in-java/

测试代码如下:
  1. public class TestGC {   
  2.   private String large = new String(new char[100000]);   
  3.   
  4.   public String getSubString() {   
  5.     return this.large.substring(0,2);   
  6.   }   
  7.   
  8.   public static void main(String[] args) {   
  9.     ArrayList<string></string> subStrings = new ArrayList<string></string>();   
  10.     for (int i = 0; i <1000000; i++) {   
  11.       TestGC testGC = new TestGC();   
  12.       subStrings.add(testGC.getSubString());   
  13.     }   
  14.   }   
  15. }   
  16.   

如果要改掉这个bug,只要改写一下getSubString的方法就好了。

  1. public String getSubString() {   
  2.     return new String(this.large.substring(0,2)); // <-- fixes leak!   
  3.   }   

我测试了一下,确实如此。然后我看了一下JDK1.5.0_06代码中String类

from JDK1.5.0_06, String class:
  1. public String substring(int beginIndex, int endIndex) {   
  2.     if (beginIndex < 0) {   
  3.         throw new StringIndexOutOfBoundsException(beginIndex);   
  4.     }   
  5.     if (endIndex > count) {   
  6.         throw new StringIndexOutOfBoundsException(endIndex);   
  7.     }   
  8.     if (beginIndex > endIndex) {   
  9.         throw new StringIndexOutOfBoundsException(endIndex - beginIndex);   
  10.     }   
  11.     return ((beginIndex == 0) && (endIndex == count)) ? this :   
  12.         new String(offset + beginIndex, endIndex - beginIndex, value);   
  13.     }  

这里用到的String的构造函数是private的

  1. private String(int offset, int count, char value[]) {   
  2.     this.value = value;   
  3.     this.offset = offset;   
  4.     this.count = count;   
  5.     }  

上面那个例子程序改写的部分其实就是增加调用public的String构造函数另外创建一个String对象,我们再来看看这个public的构造函数,已经另外一个类似上面这个private的构造函数的public构造函数:

两个public的构造函数
  1. public String(String original) {   
  2.     int size = original.count;   
  3.     char[] originalValue = original.value;   
  4.     char[] v;   
  5.     if (originalValue.length > size) {   
  6.         // The array representing the String is bigger than the new   
  7.         // String itself.  Perhaps this constructor is being called   
  8.         // in order to trim the baggage, so make a copy of the array.   
  9.         v = new char[size];   
  10.         System.arraycopy(originalValue, original.offset, v, 0, size);   
  11.     } else {   
  12.         // The array representing the String is the same   
  13.         // size as the String, so no point in making a copy.   
  14.         v = originalValue;   
  15.     }   
  16.     this.offset = 0;   
  17.     this.count = size;   
  18.     this.value = v;   
  19.     }   
  20.          
  21. public String(char value[], int offset, int count) {   
  22.         if (offset < 0) {   
  23.             throw new StringIndexOutOfBoundsException(offset);   
  24.         }   
  25.         if (count < 0) {   
  26.             throw new StringIndexOutOfBoundsException(count);   
  27.         }   
  28.         // Note: offset or count might be near -1>>>1.   
  29.         if (offset > value.length - count) {   
  30.             throw new StringIndexOutOfBoundsException(offset + count);   
  31.         }   
  32.         char[] v = new char[count];   
  33.         System.arraycopy(value, offset, v, 0, count);   
  34.         this.offset = 0;   
  35.         this.count = count;   
  36.         this.value = v;   
  37.     }  

上面这两个public的构造函数,另外创建出来的String对象和原来的String对象并不共享其char数组的。而前面那个private的构造函数没有作arraycopy,是共享char其数组的。我想JDK这个实现有待商讨,内部使用的private的构造函数中不需要copy数组,可以共享数组。但private的构造函数被public的subString方法调用后,被外部使用时,就有问题了。

 以后写相关代码时要小心了! 

 

 

分享到:
评论
1 楼 zhangsheng79 2007-10-11  
java也太傻了!

相关推荐

    深入理解Java:String

    JVM主要管理两种类型内存:堆和非堆,堆内存(HeapMemory)是在Java虚拟机启动时创建,非堆内存(Non-heap Memory)是在JVM堆之外的内存。简单来说,非堆包含方法区、JVM内部处理或优化所需的内存(如JITCompiler,...

    在java性能测试中经常遇到的问题

    String和StringBuffer、StringBuilder  在java性能测试中经常遇到很多的问题,Jason对代码端的非常常见的问题留下点Memory。  String和StringBuffer、StringBuilder  在循环中使用“+”来连接String将大大降低...

    Memory Analyzer(5积分)

    java分析工具(memory analyzer)是款功能非常强大的java监控分析工具;这款软件是作为跨平台的开源工具进行使用的,软件可以快速的进行分析您的内存问题,也可以进行监控整个的Java 应用程序的姿态和行为,并且还可以...

    JAVA看不了string源码-JavaScript-memory-leak-checker:MemoryLeakChecker可以检查Jav

    JAVA看不了字符串源码用法 源memory_leak_checker.js和来自JavaScript的调用: MemoryLeakChecker(window) 这将分析每个对象并列出并输出具有200多个元素的任何对象或列表。 这对于查找数据结构中的泄漏可能非常有用...

    java在cpu的占有率

    private long javacount; /** 可使用内存. */ private long totalMemory; /** 剩余内存. */ private long freeMemory; /** 最大可使用内存. */ private long maxMemory; /** 操作系统. */ private ...

    Simple-Memory-Compiler:易于使用的无文件Java编译器

    简单内存编译器 这是javax.tools.JavaCompiler的... " public static void main(String args[]) { " + " A.print( \" Hello from an inner class \" ); " + " } " + " public static class A { " + " public stati

    myths-about-java:这个项目是出于对Java的“本地”开发人员的沮丧而开始的

    关于java的神话 这个项目是出于对Java的“本地”开发人员的沮丧而开始的 内存消耗 纯Java 由阻塞2分钟的一个“哑”主类组成 package org.deer.java8.memory.consumption ; import java.util.concurrent.TimeUnit ; ...

    javacv-platform-1.3.3-src

    // buffer wrapped around the memory pointed by imageData, and under Android we can // also use that Buffer with Bitmap.copyPixelsFromBuffer() and copyPixelsToBuffer(). // - To get a BufferedImage ...

    java编写的计算器,能实现加减乘除

    aboutCal = new JMenuItem(" 关于计算器(A)"); aboutCal.setForeground(Color.MAGENTA); aboutCal.addActionListener(this); myCollege =new JMenuItem(" 进入我的学院(W)"); myCollege....

    Practical Java(中文版(繁体+简体))

    實踐31:如欲進行字符串接合,StringBuffer優於String 107 實踐32:將對象的創建成本(creation cost)降至最小 109 實踐33:慎防未用㆖的對象(unused objects) 114 實踐34:將同步(synchronization)減至最低 ...

    SimpleCache:用Java实现的缓存框架,使用HashMap进行存储,你可以实现Cache和CacheFactoryStrategy来自定义你的缓存实现逻辑

    SimpleCacheA Cache framework for java and android application, objects are store in key-value pair in memory,value can be any java object like String, List, Map etc. you can define your store logic ...

    java sigar获得服务器信息

    public static void main(String[] args) { try { // System信息,从jvm获取 property(); System.out.println("----------------------------------"); // cpu信息 cpu(); System.out.println("------------...

    java.lang.IllegalArgumentException:Input == null的异常处理

    问题如下; java.lang.ExceptionInInitializerError Caused by: java.lang.IllegalArgumentException: input == null! at javax.imageio.ImageIO.read(ImageIO.java:1388) at ...

    linux系统安装oracle数据库详解

    Exception in thread “main” java.lang.UnsatisfiedLinkError: /tmp/OraInstall2009-11-25_02-34-42PM/jre/1.4.2/lib/i386/libawt.so:libXp.so.6: cannot open shared object file: No such file or directory ...

    Note_scalad.tar.gz

    Java_Memory Java_Node Java_Photo_Base64AndZip Java_Request_GetIP Java_Shiro_Session Java_Singleton Java_Transient Java_URLConnection_File_Download Java_Volatile Java_jmap_histo_pid Java_jmeter_server_...

    Android代码-guava

    Guava: Google Core Libraries for Java Guava is a set of core libraries that includes new collection types (such as multimap and multiset), immutable collections, a graph library, functional types, ...

    evergreen:Java进程间持久性内存映射对象

    ====== Java进程间持久性内存映射对象 实现的功能 使用内存映射文件(MMF); 线程安全的Evergreen 对象; 当跨多个JVM(通过使用目标MMF上的锁定位)进行访问时,可以安全地读取/写入文件中的已保存实例。 低...

    GeoLiteCity.dat

    在Java中想要使用这个数据文件需要下载相应的Jar包和dat文件: GeoIP jar包:geoip-api-1.3.1.jar Geo city dat文件:GeoLiteCity.dat 把dat文件放在自己的本地目录,然后项目中导入geoip.jar即可: import ...

    jsp探针 ver0.1

    private final String windowsParseMacAddress(String ipConfigResponse) throws java.text.ParseException { String localHost = null; try { localHost = java.net.InetAddress.getLocalHost().getHostAddress(); ...

    Jodis:Jodis,Java对象字典服务器,就像Redis一样

    用于存储普通的串口,可以基于java.lang.String。 列表对象,脆弱基于java.util.List; 哈希表结构,一直基于java.util.Map; 集合结构,暂时基于java.util.Set; 有序集合结构,并基于java.util.Map和跳跃表。 单...

Global site tag (gtag.js) - Google Analytics