Writing in the front
The question of how much memory the Java String class occupies is one of the most frequently asked questions in recent interviews. Many of the answers of friends are not very correct, some say that does not take up space, some say 1 byte, some say 2 bytes, some say 3 bytes, some say do not know, more funny is actually some people say 2 to the 31st power. If that’s the case, the server doesn’t have enough memory to fit a string. As programmers, we can’t make jokes like that. Today, let’s talk about how much memory a String occupies in Java!
Structure of Java objects
First, let’s take a look at the structure of Java objects in the virtual machine. Here, take HotSpot virtual machine as an example.
Note: Image source: http://r6d.cn/wp7q
As can be seen from the above figure, the structure of the object in memory mainly consists of the following parts:
- Mark Word: The Mark Word part of the object is 4 bytes and contains a series of tag bits, such as lightweight lock tag bits, biased lock tag bits, and so on.
- Klass Pointer (Class object Pointer) a Class object Pointer is also 4 bytes in size and points to the memory address of the corresponding Class object (its corresponding metadata object)
- Object actual data: this contains all member variables of the object. The size is determined by the size of each member variable. For example: Byte and Boolean are 1 byte, short and char are 2 bytes, int and float are 4 bytes, long and double are 8 bytes, and reference is 4 bytes
- Alignment: The last part is the alignment of the filled bytes, which are filled by 8 bytes.
Or to put it another way:
- Object header: 8 bytes (holds the object’s class information, ID, and state in the VIRTUAL machine)
- Java primitive data: data of types such as int, float, char, etc
- Reference: 4 bytes
- Padding character
A String in Java
Space occupied by an empty String
Here, we take Java8 as an example. First, let’s look at the member variables in the String class.
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
Copy the code
Arrays are also objects in Java, so arrays also have object headers. So, the space taken up by an array is the space taken up by the object header plus the length of the array plus the reference to the array, which is 8 + 4 + 4= 16 bytes.
So, we can figure out how much memory an empty String takes up, as shown below.
Object (8Bytes) + reference (4Bytes) +charArray (16Bytes) +1aint(4Bytes) +1along(8Byte) =40byteCopy the code
So, guys, are you right?
Space occupied by a non-empty String
If the length of a String is greater than 0, we can calculate the memory usage of the String as shown below.
40 + 2 * n
Copy the code
Where n is the length of the string.
Now, some of you might say, why is it 40 plus 2 times n? This is because 40 is the memory space occupied by an empty String, which we’ve already explained above. The String class actually stores data in the char[] array, and a single char in the char[] array takes up 2 bytes, so, The data in the String alone takes up 2 * N (n is the length of the String) bytes of space, plus the 40 bytes of space used by the empty String, resulting in the storage space used by a String: 40 + 2 * N (n is the length of the String).
Therefore, when using strings extensively in your code, you should consider the actual memory footprint.
Note: The 40 + 2 * n formula can be regarded as a general formula for calculating how much memory a String takes up.
Verify the conclusions
Next, let’s test the above conclusion. First, create a UUIDUtils class to generate a 32-bit UUID, as shown below.
package io.mykit.binghe.string.test;
import java.util.UUID;
/ * * *@author binghe
* @version 1.0.0
* @descriptionGenerates UUID */ without -
public class UUIDUtils {
public static String getUUID(a){
String uuid = UUID.randomUUID().toString();
return uuid.replace("-".""); }}Copy the code
Next, create a TestString class, create an array of length 4000000 in the main() method, and fill the array with UUID strings, as shown below.
package io.mykit.binghe.string.test;
import java.util.UUID;
/ * * *@author binghe
* @version 1.0.0
* @descriptionTests the memory space occupied by String */
public class TestString{
public static void main(String[] args){
String[] strContainer = new String[4000000];
for(int i = 0; i < 4000000; i++){
strContainer[i] = UUIDUtils.getUUID();
System.out.println(i);
}
// Prevent the program from exiting
while(true) {}}}Copy the code
In this example, there are 4000000 character strings, and each character string is 32 characters in length. Therefore, the memory space occupied by saving character string data is :(40 + 32 * 2) * 4000000 = 416000000 bytes, which is about 416MB.
We used the Jprofiler memory analysis tool for analysis:
As you can see, using the Jprofiler memory analysis tool, the result is 321MB + 96632KB, which is approximately 417MB. The reason why the Jprofiler’s results are larger than our calculations is that during the actual execution of the program, some strings are generated inside the program, and these strings also take up memory space!
Therefore, the results obtained using the Jprofiler memory analysis tool are in line with our expectations.
If you have any questions, you can leave a comment below or add me to wechat: SUN_shine_LYz. I will pull you into the group. We can exchange technology together, advance together, and make great force together