简体   繁体   English

如何使用字符串有效地管理内存?

[英]How to efficiently manage memory using Strings?

Consider a sample piece of code. 考虑一段示例代码。

public void testString()
{     
    int i = 0;
    while(i < 100000000)
    {
        String s ="Hi hello bye" +i;
        i++;          
    }
}

In each iteration, a new String is created and its value is no longer needed for the next iteration. 在每次迭代中,都会创建一个新的String,并且下一次迭代不再需要它的值。 I tried printing the memory consumed pre and post this testString() functionality. 我尝试打印之前消耗的内存并发布此testString()功能。 Here are their values. 这是他们的价值观。

Before invoking testString():

Total Memory: 91684864 (87.4375 MB)
Max Memory:   1360855040 (1297.8125 MB)
Free Memory:  72163552 (68.82052612304688 MB)

After invoking testString():
Total Memory: 424280064 (404.625 MB)
Max Memory:   1360855040 (1297.8125 MB)
Free Memory:  171766816 (163.80960083007812 MB).

I see a large amount of memory being used and am afraid JVM Heap may go out of bounds due to the current way of handling Strings. 我看到使用了大量内存,并且由于当前处理字符串的方式,我担心JVM堆可能会超出范围。 The String generated for iteration 1 is no longer needed in iteration 2 and its storage space can be freed. 在迭代2中不再需要为迭代1生成的字符串,并且可以释放其存储空间。 I believe that is not happening here. 我相信这不会发生在这里。

I tried using StringBuffer and StringBuilder objects and there seems a very marginal improvement in the memory usage. 我尝试使用StringBuffer和StringBuilder对象,内存使用情况似乎有很小的改善。

Kindly assist me a better and optimal approach. 请帮助我更好,更好的方法。

The String generated for iteration 1 is no longer needed in iteration 2 and its storage space can be freed. 在迭代2中不再需要为迭代1生成的字符串,并且可以释放其存储空间。 I believe that is not happening here. 我相信这不会发生在这里。

It definitely is happening. 它肯定正在发生。

You're creating 100 million strings, each of which is at least 13 characters - and most of which will be about 20 characters. 你创造了1亿个字符串,每个字符串至少有13个字符 - 其中大部分都是大约20个字符。 Each string consists of an object (which has overhead) and a char[] - so I'd guess at it taking around 60 bytes for a 20-character string. 每个字符串由一个对象(有开销)和一个char[] - 所以我猜它占用大约60个字节的20个字符的字符串。

If garbage collection weren't being effective, 100 million objects requiring 60 bytes each would require 6GB - whereas you're seeing a total memory which is only about 300MB larger than it was to start with. 如果垃圾收集无效,那么每个需要60个字节的1亿个对象需要6GB - 而你看到的总内存只比开始时大约300MB。

The strings are being collected - just not immediately . 该字符串正在收集-只是没有马上

You haven't told us what you need to do with the strings in your real code (I'm assuming there's a real motivation for this) - assuming you actually need a string in each iteration of a loop, I don't think using StringBuilder is going to help you. 您还没有告诉我们您需要对实际代码中的字符串做什么(我假设有一个真正的动机) - 假设您在循环的每次迭代中实际上需要一个字符串,我不认为使用StringBuilder会帮助你。 If you only need the data is a StringBuilder then you can make it a lot more efficient, but it's rare that you create a StringBuilder but don't call toString on it. 如果你需要数据是一个StringBuilder那么你可以使它更有效率,但很少你创建一个StringBuilder但不要在其上调用toString

What will happen on the first run 第一次运行会发生什么

JVM runs the code, generates the strings, and at certain intervals the Garbage Collector frees the used memory. JVM运行代码,生成字符串,并在一定的时间间隔内垃圾收集器释放已用内存。 Beside some wasted execution time, the program will run normally. 除了一些浪费的执行时间,程序将正常运行。

What will happen if the function is called frequently 如果频繁调用该函数会发生什么

JVM will begin to optimize the loop, realize that nothing is done with those strings ever and marks the entire function as dead code. JVM将开始优化循环,意识到没有对这些字符串做任何事情,并将整个函数标记为死代码。 Eventually calling the function will do literally nothing, as the JVM converted the content to a simple return 最终调用该函数几乎没有任何作用,因为JVM将内容转换为简单的return

Kindly assist me a better and optimal approach. 请帮助我更好,更好的方法。

Since even the JVM has no clue what your code is supposed to do... what is it what you want to do? 因为即使是JVM也不知道你的代码应该做什么......你想做什么? There might be an optimal solution for your actual problem at hand, that is very different from the code sample that you posted initially. 对于您手头的实际问题,可能有最佳解决方案,这与您最初发布的代码示例非常不同。

It depends on how you used StringBuilder. 这取决于你如何使用StringBuilder。 This 这个

    StringBuilder sb = new StringBuilder("");
    while (i < 100000000) {
        sb.delete(0, sb.length());
        sb.append("Hi hello bye").append(i);
        i++;
    }

will be much more efficient both in memory consumption and speed 在内存消耗和速度方面都会更有效率

String is immutable, when you going to add a string continuously which is create a string object for every iteration, so memory has been exceed. 字符串是不可变的,当你要连续添加一个字符串时,它会为每次迭代创建一个字符串对象,因此内存已超出。 if you use StringBuilder, it works in single object even it handles more than one iteration is happen. 如果你使用StringBuilder,它在单个对象中工作,即使它处理多个迭代也会发生。 StringBuilder is mutable. StringBuilder是可变的。

StringBuilder iter = new StringBuilder("");
while (i < 100000000) 
{
    iter.delete(0, iter.length());
    iter.append("Hi hello bye").append(i);
    i++;
} 

The JVM should never run out of heap memory from unreferenced objects, such as the strings in your example program, because before it throws an OutOfMemory exception, it will run garbage collection. JVM永远不会从未引用的对象(例如示例程序中的字符串)中耗尽堆内存,因为在它抛出OutOfMemory异常之前,它将运行垃圾收集。 See the semantics of this exception from the Java Virtual Machine Specification, section 6.3 : 请参阅Java虚拟机规范第6.3节中的此异常的语义:

OutOfMemoryError: The Java Virtual Machine implementation has run out of either virtual or physical memory, and the automatic storage manager was unable to reclaim enough memory to satisfy an object creation request. OutOfMemoryError:Java虚拟机实现已用完虚拟或物理内存,并且自动存储管理器无法回收足够的内存来满足对象创建请求。

Usage of string builders is the best option you have. 使用字符串构建器是您的最佳选择。 Since the number of strings/string builders required by you are huge in number, you can not expect JVM to virtually avoid using much of a memory in any case. 由于您所需的字符串/字符串构建器数量巨大,因此您无法期望JVM在任何情况下都可以避免使用大量内存。 Referring to your statistics above: 参考上面的统计数据:

With use of string: % of free memory on total memory is 40.48% ((163.80960083007812 MB/404.625 MB )*100) . 使用字符串:总内存的可用内存40.48% ((163.80960083007812 MB/404.625 MB )*100)40.48% ((163.80960083007812 MB/404.625 MB )*100)

With use of string builders: % of free memory on total memory is 69.35 % ((252.659 MB/364.3125 MB)*100) , which is quite a significant improvement. 使用字符串构建器:总内存的可用内存69.35 % ((252.659 MB/364.3125 MB)*100)69.35 % ((252.659 MB/364.3125 MB)*100) ,这是一个非常显着的改进。 Also, usage of the above variable is only inside the scope of loop, therefore JVM's garbage collector will run to clear the memory once required. 此外,上述变量的使用仅在循环范围内,因此JVM的垃圾收集器将在需要时运行以清除内存。

Since scope of variable is just for the iteration of while loop, so here you don't need to worry about memory overflow as on next Garbage Collector execution it will free all the memory: 由于变量的范围仅适用于while循环的迭代,因此在这里您不必担心内存溢出,因为在下一次垃圾收集器执行时它将释放所有内存:

while(i < 100000000)
{
    String s ="Hi hello bye" +i;
    i++;          
}// no more required the s afterward

In each iteration String s will create a new object and but previous one is not required now, so it is in memory until Garbage collector clean it. 在每次迭代中,String将创建一个新对象,但现在不需要前一个,所以它在内存中,直到垃圾收集器清理它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM