我是靠谱客的博主 坚定鸭子,最近开发中收集的这篇文章主要介绍Jvm内存结构与垃圾回收算法Jvm内存模型Jvm分区如何把手动把常量放到常量池(方法区);,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
Jvm内存结构与垃圾回收算法
- Jvm内存模型
- 各个区域简述
- Jvm分区
- 垃圾回收算法
- 如何把手动把常量放到常量池(方法区);
Jvm内存模型
由类加载器加载类信息,保存到方法区里面;
实例化对象放到堆里面
方法局部变量放到虚拟机栈里(临时变量)
局部变量表存放的是 8 大基础类型加上一个引用(句柄)类型,所以还是一个指向地址的指针
句柄:我们需要访问堆里面的数据,由句柄指向堆里面的数据,相当于C里面的指针;
指针:直接指向地址:
句柄:中间有一个变量表存储管理类的信息,句柄指向变量表中的类;
各个区域简述
- 方法区: 主要存储类的信息,常量池(static常量和static变量)和编译后的字节码数据; (static变量也属于类的一个信息资料)
- 堆: 初始化对象,成员变量,所有的对象实例和数组都需要在堆里面分配内存!(数组并不是基础变量,那也是一个对象)
- 栈: 由本地方法栈和虚拟机栈组成
- 虚拟机栈:栈的结构由栈帧组成,每调用一个方法,把方法放在栈顶执行,执行完后返回结果变成前一个栈帧里的一个变量;
(虚拟机栈由:局部变量表,操作数栈,方法出口组成等) - 本地方法栈: 主要调用本地方法(其他语言的之类的,比如c++,Native 方法等) (JVM可能有多个语言组成)
- 虚拟机栈:栈的结构由栈帧组成,每调用一个方法,把方法放在栈顶执行,执行完后返回结果变成前一个栈帧里的一个变量;
- 程序计数器:当线程切换时候,通过程序计数器来确定当前执行的位置,通过改变计数器进程流程控制;
Jvm分区
垃圾回收算法
前提概念:
引用根节点:指一个标记节点,以此节点开始标记所有被引用的节点
内存碎片:在储存分配过程中产生的、不能供用户作业使用的主存里的小分区称成“内存碎片”。对象实例化分配内存,对象回收时清理内存造成断断续续的现象;如下图
分配内存后如上图满的; 清理后: 如下图
中间多了一块内存,如果此时要分配一个大的内存F,会没有内存可分配,造成内存碎片
- 标记清除算法: 第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,清除未被标记的对象; 该算法为同步算法,清理时会暂停其他所有线程;
- 标记整理算法:第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆清除未被标记的对象,然后把剩余的对象向左移动对齐;(多了一个整理操作,因此成本更高,但是却解决了内存碎片的问题)
- 复制算法:将内存分为二块区域(设A区域,B区域),A存活的对象放到B里去,然后清理A,下一轮B存活的对象放到A里面去,清理B;此方法会造成一半内存空间的浪费,但是有效解决了内存碎片的问题;
- 分代收集:分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。一般情况下将堆区划分为老年代(Tenured Generation)和新生代(Young Generation);老年代的特点是每次垃圾收集时只有少量对象需要被回收,而新生代的特点是每次垃圾回收时都有大量的对象需要被回收,那么就可以根据不同代的特点采取最适合的收集算法。新生代的会经过多次最终到达老年代,在一些JVM版本上,老年区的对象会经历几次周期最终到达永久代上;
如何把手动把常量放到常量池(方法区);
运行时常量池相当于 Class 文件常量池具有动态性,Java 语言并不要求常量一定只有编译期间才能产生,运行期间也可以将新的常量放入池中,String 类的 intern()方法就是这样的;
public class Main {
public static void main(String[] args) {
String s1 = new StringBuilder("go").append("od").toString();//这里是对象放在堆里,并没有放到常量池
s1.intern();//放入常量池
String s2 = "good";
System.out.println(s2 == s1);//输出true
}
}
最后
以上就是坚定鸭子为你收集整理的Jvm内存结构与垃圾回收算法Jvm内存模型Jvm分区如何把手动把常量放到常量池(方法区);的全部内容,希望文章能够帮你解决Jvm内存结构与垃圾回收算法Jvm内存模型Jvm分区如何把手动把常量放到常量池(方法区);所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复