JVM虚拟机拿到内存后对内存进行割分
栈、局部方法栈和程序计数器是线程私有的
堆、方法区是线程公有的
栈: 主要用于存储方法的局部变量 (基本数据类型)
堆: 存储Java应用程序中创建的对象和数组,因为是公有的(全局共享),所有线程都可以访问它,因此它需要有效的垃圾回收机制来管理内存的分配和释放。也就是GC。
本地方法栈:用来存储c++(等其它语言)的native方法栈区
程序计数器:指向程序当前运行的位置,就相当于存档
方法区:存放静态变量,类加载器等全局的信息(数据全局共享)
代码举例1:
func1中的方法会在运行结束后就从栈中按先进先出的方式删除
所以最后就剩a=10,打印出来的结果也就是10
代码举例2:
下面这段代码也同样,a,b,p对象都放在栈中,p存储的是对象的地址
因为name是String引用类型,所以还会在栈中再开辟一块空间存放
当方法结束后栈中会删除这些数据,但是堆中不会删除,有些对象也会被引用,所以就导致堆中可能要爆
GC过程:
GCRoot:
- 被栈直接或间接引用
- 本地方法栈直接或间接引用
- 被方法区静态或常量直接或间接引用的(全局)
GCroot符合这三条中的其中之一的都不能被删除
三种清理方法:
1.标记——清理: 被标记上的就清理掉
缺点:内存碎片
2.标记——整理: 清理掉被标记的并且把空间都集中(把其他对象都往前挪)
缺点:代价大,每次删除都要挪全部的对象
3.复制: 将整个内存一分为二,将不需要删除的复制到2区,这样就可以避免空间碎片
缺点:2倍内存
实际GC过程:
年轻代分为三个区:
S区:survive区幸存者区,一个To区,一个From区,(谁是空的谁就是To区)
E区:伊甸园,生命开始的地方;新new的对象都放在E区
当对象要将E区填满的时候就会触发GC
过程:
年轻代:
当E区快满的时候,标记的所有对象都会转移到S1区,同时系统会把S2区和E区看为一个整体将里面的东西全部删除。下次E区快满时,将标记的对象复制到S2区中,将S1和E区的对象删除,就这样循环往复。
E+S1复制到S2
E+S2复制到S1
E+S1复制到S2
老年区:主要存放大对象和age>=6的对象
每次对新生代中对象复制的时候都会进行标记,如果幸存年龄就会+1,年龄大于等于6时就会进入老年代。(这意味着这个对象可能在以后100次200次GC中都能存活下来)
当老年代中对象满了:
就会触发第一种或第二种清理方式:
1.标记——清理
2.标记——整理