How to use less memory when assigning a large new line

The Java string is immutable, therefore

when you create a string, a memory block is assigned to it on the heap, and when you change its value, a new memory block is created for this string, and the old one has the right to garbage collection for example

String str = func1_return_big_string_1()"; //not literal String str= func2_return_big_string_2()"; //not literal 

But since garbage collection takes time to strike, so we almost have memory on the heap containing both large lines 1 and 2. They can be a problem for me if this happens a lot.

Is there a way to make large line 2 to use the same memory in line 1, so we don’t need to have extra space when we assign large line 2 to str.

Edit: Thanks for all the input, and in the end, I realized that I should not expect Java code to behave like C ++ code (i.e. a different amount of memory). I wrote a C ++ 11 demo that works as expected, the largest memory capacity is around 20 M (the largest file I tried to download) using the rvalue link and the redirect destination operator, as expected. The following demo is done in VS2012 with C ++ 11.

 #include "stdafx.h" #include <iostream> #include <string> #include <vector> #include <fstream> #include <thread> using namespace std; string readFile(const string &fileName) { ifstream ifs(fileName.c_str(), ios::in | ios::binary | ios::ate); ifstream::pos_type fileSize = ifs.tellg(); ifs.seekg(0, ios::beg); vector<char> bytes(fileSize); ifs.read(&bytes[0], fileSize); return string(&bytes[0], fileSize); } class test{ public: string m_content; }; int _tmain(int argc, _TCHAR* argv[]) { string base("c:\\data"); string ext(".bin"); string filename; test t; //std::this_thread::sleep_for(std::chrono::milliseconds(5000)); cout << "about to start" << endl; for(int i=0; i<=50; ++i) { cout << i << endl; filename = base + std::to_string(i) + ext; //rvalue reference & move assignment operator here //so no unnecessary copy at all t.m_content = readFile(filename); cout << "szie of content" << t.m_content.length() << endl; } cout << "end" << endl; system("pause"); return 0; } 
0
java string memory
source share
5 answers

To avoid using the old and new lines in memory at the same time, you can explicitly allow GC to clear it by setting the variable null variable:

 String str; str = func1_return_big_string_1(); str = null; // Now, GC can clean, when it needs extra memory for the String. str = func2_return_big_string_2(); 

UPDATE:. To support my claim, I wrote a test case that proves I'm right: http://ideone.com/BwGfSN . The code demonstrates the difference between (using Finalizer):

 GCTest test; // Without the null assignment test = create(0); test = create(1); test = null; System.gc(); try {Thread.sleep(10);} catch (Exception e){} System.out.println(); // With the null assignment test = create(2); test = null; test = create(3); test = null; System.gc(); 
+1
source share

Use StringBuffer, StringBuffer.append ()

+2
source share

I see several options:

  • Use char[] .
  • Copy StringBuilder to your version of MyStringBuilder using a public reusable buffer. The main disadvantage is the lack of regular expressions. This is what I did when I needed to improve performance.
  • Hack for JDK <= 6: There is a protected constructor for reusing char string / packet buffers. This is no longer for JDK 7+. You have to be very careful with this, and this is not a problem when you have a C / C ++ background.
  • Copy String to MutableString with a public reusable buffer. I do not think that there will be a problem with adding a custom regular expression, since there are many available.
+2
source share

This is not a big deal for non-interned strings. If you run out of memory, the garbage collector will delete all objects that are no longer referenced.

Interned strings are much more difficult to collect, see Garbage collection of string literals for details

EDIT Uninterrupted string as a regular object. Once there are no more links to it, it will receive garbage collection.

if str is the only link on the left pointing to the original string, and str modified to point to something else, then the original string has the right to garbage collection. Therefore, you no longer need to worry about running out of memory, because the JVM will collect it if memory is required.

+1
source share

I just found a MutableString . It is available at Maven Central . Here is an excerpt from their JavaDoc page:

  • Variable strings take up little space - their only attributes are an array of support characters and an integer;
  • their methods try to be as efficient as possible: for example, if the restriction on a parameter is implied by restricting access to the array, we do not check it explicitly, and Bloom filters are used to speed up multi-character substitutions;
  • they allow you to directly access the support array (at your own peril and risk);
  • they implement CharSequence, therefore, for example, you can match or split a variable string into a regular expression using the standard Java API;
  • they implement Appendable , so they can be used with Formatter and similar classes;

UPDATE

You can use the Appendable interface of this MutableString to read a file with almost zero memory (8K, which is the default buffer size in Java). With Guava CharStreams.copy, it looks like this:

 MutableString str = new MutableString((int) file.length()); CharStreams.copy(Files.newReaderSupplier(file, Charset.defaultCharset()), str); System.out.println(str); 

Full working example .

+1
source share

All Articles