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

关于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和StringBuffer的区别实例详解

    Java中String和StringBuffer的区别实例详解 Java中String和StringBuffer都是用来存储字符串的对象,但是它们之间有着很大的区别。下面我们来详细介绍Java中String和StringBuffer的区别实例详解。 首先,String是不...

    memory-efficient-java-tutorial

    - **IBM的研究背景**:IBM的研究团队在过去十年中一直在诊断大型Java系统的内存和性能问题,并为此开发了一系列诊断工具,如Yeti等。他们与众多开源项目、大型商业应用及软件产品合作,涉及服务器端、客户端等多种...

    java_memory_tunning.zip_memory

    这份名为"java_memory_tunning.zip_memory"的压缩包提供了一个关于Java内存调优的指南,主要聚焦于如何优化Java虚拟机(JVM)的内存配置以提升系统效率。以下是基于这个主题的详细知识点讲解: 1. **Java内存模型**...

    深入理解Java:String

    Java中的字符串(String)是编程中不可或缺的部分,深入理解其内在机制对于提高代码性能至关重要。本文将探讨Java中字符串的内存管理,尤其是与Java虚拟机(JVM)内存模型的关联。 首先,Java内存模型分为堆内存...

    string-concatenate-outofmemory.rar_crash

    "string-concatenate-outofmemory.rar_crash" 这个标题暗示了一个与字符串连接(concatenation)有关的问题,可能在特定条件下导致程序崩溃。描述中提到的测试目标是检查连续的字符串拼接是否会抛出异常,而不是直接...

    完美解决java读取excel内存溢出问题.rar

    在Java开发中,处理大型Excel文件时,可能会遇到内存溢出的问题。这通常是由于Java的默认内存设置不足以处理大量数据导致的。本解决方案主要针对使用Apache POI库进行Excel读取时遇到的这类问题。 首先,Apache POI...

    关于(java heap space)内存溢出的解决办法

    在Java编程中,"java heap space"内存溢出是一个常见的问题,它通常发生在应用程序尝试分配超过JVM堆内存限制的对象时。这个问题对于任何Java开发者来说都至关重要,因为如果不妥善处理,可能会导致程序崩溃。以下是...

    Java jdk22安装包

    Java 22 (Oracle JDK 22) 在性能、稳定性和安全性方面进行了数千种改进,包括对Java语言、其API和性能,以及Java开发工具包(JDK)中工具的增强功能,以帮助开发人员提高工作效率。全新版本的 JDK 更新和改进了 12 ...

    java中的日期处理类总结:DateCalendarGregorianCalendarDateFormatSimpleDateFormat类

    ### Java中的日期处理类总结:Date、Calendar、GregorianCalendar、DateFormat、SimpleDateFormat 在Java编程中,日期时间处理是常见的需求之一。为了更好地理解和使用Java中的日期处理类,本篇文章将对Date、...

    Java获取计算机CPU、内存等信息

    在Java编程中,获取计算机的硬件信息,如CPU使用率和内存使用情况,是一项常见的需求。这主要应用于系统监控、性能分析以及资源管理等方面。Java虽然不像C++或C#那样可以直接调用操作系统API,但它提供了Java ...

    Memory Management Simulator

    内存管理是计算机科学中的核心概念,特别是在编程语言如Java中,它对于程序的性能和稳定性至关重要。"Memory Management Simulator" 是一个模拟器,用于帮助理解并可视化内存管理的过程。这个模拟器利用了Java Swing...

    java csv大数据量导出(千万级别,不会内存溢出)

    此外,为了避免内存中的临时数据过多,还可以考虑使用Java的内存映射文件(Memory-Mapped File)。通过MappedByteBuffer,我们可以让操作系统负责数据的缓存和页面交换,这在处理大文件时能显著降低内存使用。 在...

    JAVA 认证 考试题目

    在上面的题目中,选项 3"可以声明一个空类"是正确的,因为在 JAVA 中,可以声明一个不包含任何成员变量或方法的空类。 三、JAVA 注释方法 在 JAVA 中,注释方法可以分为三种:单行注释、多行注释和文档注释。单行...

    使用Java编写不含任何BUG的计算器

    在项目压缩包`CalculatorDemo.java`中,应包含上述所有逻辑的完整实现,以及可能的测试用例或示例代码,以确保所有功能的正确性。编写代码时,应遵循良好的编程实践,如注释、命名规范、代码复用等,以提高代码...

    Java.NIO资源下载资源下载

    根据提供的文件信息,我们可以提取并总结出关于Java NIO(New Input/Output)的重要知识点。 ### Java NIO 概述 Java NIO 是 Java 平台的一个重要特性,首次出现在 Java 1.4 版本中。它为 Java 开发者提供了一套...

    java获取cpu、内存信息

    在Java编程中,获取CPU和内存信息是系统监控和性能分析的重要部分。下面将详细介绍如何使用Java来实现这一目标。 首先,我们从CPU信息开始。Java提供了`java.lang.management`包,该包中的`OperatingSystemMXBean`...

    java实现文本输出Excel

    在Java编程语言中,将普通文本转换为Excel文件是一项常见的任务,特别是在数据分析、报表生成或者数据导出场景中。这个例子提供了一种方法,通过Java API来实现这一功能。主要涉及的技术点包括对Apache POI库的使用...

    java高速文件缓存

    Java高速文件缓存是一种优化应用程序性能的技术,它通过将经常访问的数据存储在内存中,以减少对硬盘或网络I/O的依赖,从而显著提高数据读取速度。在Java中实现高效的文件缓存策略,可以利用Java集合框架、内存管理...

    Java工程师成神之路~-HollisChuang's Blog1

    最后,深入理解泛型、继承和自动装箱拆箱,以及如何实现回调机制,这些都是Java编程中的高级主题。同时,掌握字节码层面的知识,可以让我们更深入地理解Java的运行机制。 通过以上学习,你将能够踏上Java工程师的成...

    java9开发文档中文版.rar

    Java 9还包括了许多其他的小改进和API扩展,如`String`的`strip()`和`stripIndent()`方法,`OptionalInt`, `OptionalLong`和`OptionalDouble`的静态工厂方法,以及`ProcessHandle`的增强等。 以上只是Java 9开发...

Global site tag (gtag.js) - Google Analytics