参考:
(1)浅谈java垃圾回收机制:
https://www.cnblogs.com/mxlandxt/p/6972252.html
我:
一、内存的管理
(1)在java中,内存的管理可分为 栈(Stack)、堆(Heap )和 方法区(PermGen),方法区又可分为数据段(Data Segment) 和 代码段(Code Segment)。
二、堆heap(先进先出)和 栈stack
(1)堆和栈存储在JVM虚拟机的RAM(随机访问存储器)中,而非RAM存储(硬盘等永久存储空间)是用于存放 持久化对象 的。
(2)栈内存:是单个线程的私有内存,用来存储局部变量(基本数据类型:int、short、double、long、float、boolean、char、byte;注意没有String)和方法调用;
当没有引用指向栈中的某个数据时,该数据就会消失。
栈的优势:存取速度比堆快。
(3)堆内存:可以被所有线程访问,用来存储java中的对象(即java对象可以被所有线程访问),无论是成员变量、局部变量、还是类变量,它们指向的对象都存储在堆内存中。
堆中的对象由垃圾回收器负责回收,因此其大小和生命周期不需要确定,具有很大的灵活性。
(4)数据段:
(4.1)通常是指用来存放程序中已初始化的全局变量的一块内存区域。
(4.2)数据段属于 静态内存分配。
(4.3)字符串常量 和 静态常量 全部存放在data segment里。
(5)代码段:用于 存放代码。
(6)常量池:
(6.1)string字符串常量池在内存中的位置
(6.2)常量池在java中用于保存在编译期已确定的、已编译的class文件中的一份数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量,如String s = "java"这种声明方式;执行器产生的常量也会放入常量池,故认为常量池是JVM的一块特殊的内存空间。
(6.3)为了确保常量的安全性(当其被多个变量引用的时候),常量池实施了一套保护机制:常量池中的常量不允许被改变。就算要改变某个变量的值为某个常量,也只是先在常量池中查看是否存在此常量,是则该变量指向它,否则创建它,再让该变量指向它。
(6.4)==比较的是对象的地址,也就是是否是同一个对象。equals比较的是对象的值。
(6.5)String对象的引用都是存储在栈中的。
(6.6)对于字符串,如果是**编译期已经创建好的(直接用双引号定义的)就存储在常量池中,如 “china”。
(6.7)对于字符串,如果是运行期(new出来的)**才能确定的就存储在堆中,如 new String(“china”)。
(6.8)对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。
三、垃圾回收
四、作为方法参数时,基本数据类型与对象的区别
(1)基本数据类型(传值调用:是对 值 的拷贝)。
(2)对象引用(引用调用:是对 引用句柄 的拷贝)。
五、程序变量表示的数据存储在哪里?
(1)存储在虚拟内存中(进程的虚拟地址空间)。
(2)程序中用到的所有地址,都不是真实的内存地址,而是虚拟内存地址。
(3)操作系统和硬件会将虚拟内存映射成真实的内存。
(4)当程序访问的虚拟内存页(虚拟内存是分成一页一页的,比如每页4K)不在真实内存中时,就会触发缺页中断,操作系统这时再将对应的页载入到真实内存中,再重新访问。
假如真实内存满了,就将太久没有使用的页转出到磁盘当中,程序就认为自己独立拥有了几个G的虚拟地址空间。
(5)程序启动时,也不需要真的将信息载入到真实内存中,而只需要建立映射。这样**当程序运行时,就会产生缺页中断,需要的信息就会很自然地载入到真实内存中,而没有真正用到的信息可以一直保留再磁盘中。**因此就算真实内存只有1G,也可以运行4G的程序。