尚学堂百战程序员之栈、堆、方法区、常量池以及变量的内存分配

尚学堂百战程序员之栈、堆、方法区、常量池以及变量的内存分配
2018年06月02日 10:26 独一无二的楠竹

最近在看一些尚学堂面试的相关问题,发现自己对java底层变量内存的分配理解不是很透彻,于是尚学堂官网上各种找资料,于是自己也整理了一下(可能自己的理解还会有些偏差,如有错误,望指出,谢谢!!),下面分享给各位:

堆中Java虚拟机的自动垃圾回收:

引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用new产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。这也是Java比较占内存的原因。

存在栈中的数据同一个线程可以共享:

假设我们同时定义int a = 3;   int b = 3; 编 译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。接着处理int b = 3;在创建完b的引用变量后,由于在栈中已经有3这个字面值,便将b直接指向3的地址。这样,就出现了a与b同时均指向3的情况。特 别注意的是,这种字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向一个对象,如果一个对象引用变量修改了这个对象的内部状态,那么另一个对象引用变量也即刻反映出这个变化。相反,通过字面值的引用来修改其值,不会导致另一个指向此字面值的引用的值也跟着改变的情况。如上例,我们定义完a与b的值后,再令a=4;那么,b不会等于4,还是等于3。在编译器内部,遇到a=4;时,它就会重新搜索栈中是否有4的字面值,如果没有,重新开辟地址存放4的值;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。

包装类自动装箱:

例:

Integer c = 3;

Integer d = 3;

在自动装箱时,调用valueOf(int i)方法。把int变成Integer的时候,是有规则的,当你的int的值在-128-127时,返回的不是一个新new出来的Integer对象,而是一个已经缓存在堆 中的Integer对象,(我们可以这样理解,系统已经把-128到127之间的Integer缓存到一个Integer数组中去了,如果你要把一个int变成一个Integer对象,首先去缓存中找,找到的话直接返回引用给你就行了,不必再新new一个),如果不在-128-127时会返回一个新new出来的Integer对象。

除此之外其他的包装类型除了Float和Double外都实现了缓存。

String的常量池:

String ss3 = newString("china");先在常量池中查找是否有china字符串,如果没有,在常量池中创建一个此字符串对象,然后堆中再创建一个常量池中此 ”china” 对象的拷贝对象。所以可能会创建两个对象。

String str1 = "abc"; String str2= "ab"; String str3 = str2 + "c"; str1==str3是false是因为Stringstr3 = str2 + "c"涉及到变量(不全是常量,包括null)的相加,所以会生成新的对象,其内部实现是先在堆中new一个StringBuilder,然后append(str2),append("c");然后让str3引用toString()返回的对象。

对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。

String的intern()方法:

String的intern()方法会查找在常量池中是否存在一份equal相等的字符串,如果有则返回该字符串的引用,如果没有则添加自己的字符串进入常量池。

财经自媒体联盟更多自媒体作者

新浪首页 语音播报 相关新闻 返回顶部