前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >粗谈Java虚拟机之内存管理

粗谈Java虚拟机之内存管理

作者头像
g小志
发布2018-09-11 17:23:24
4640
发布2018-09-11 17:23:24
举报
文章被收录于专栏:Android常用基础Android常用基础

图片.png

1.1 Java栈

线程私有,生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。如果请求的站深度大于虚拟机所允许的深度,将抛出StackOverflowError异常,虚拟机栈在动态扩展时如果无法申请到足够的内存,就会抛出OutOfMemoryError异常。 总结:它存放的是java方法执行时的所有数据。 由栈帧组成一个栈帧代表一个方法的执行。

Java栈帧

每个方法从调用到执行完成对应一个栈帧在虚拟机中的入栈到出栈。

结构图:

image

栈帧由局部变量区、操作数栈和帧数据区组成。当虚拟机调用一个Java方法时,它从对应类的类型信息中得到此方法的局部变量区和操作数栈的大小,并根据此分配栈帧内存,然后压入Java栈中。

例如:

代码语言:javascript
复制
public static String A(){
    String str=B();(1)
    return str;
}
public static String B(){
    return "Hellow Word";
}

A方法执行时分配一个栈帧,当(1)处调用B方法是就会压如一个新的栈帧,当B()方法结束,栈帧弹出。

  • 局部变量区 局部变量区被组织为以字长为单位、从0开始计数的数组。字节码指令通过从0开始的索引使用其中的数据。类型为int, float, reference和returnAddress的值在数组中占据一项,而类型为byte, short和char的值在存入数组前都被转换为int值,也占据一项。但类型为long和double的值在数组中却占据连续的两项。 returnAddress这个基本类型被用来实现Java程序中的finally子句,Java程序员不能使用这个类型,它的值指向一条虚拟机指令的操作码。 结构图:

image

  • 操作数栈 和局部变量区一样,操作数栈也是被组织成一个以字长为单位的数组。它通过标准的栈操作访问--压栈和出栈。由于程序计数器无法被程序指令直接访问,Java虚拟机的指令是从操作数栈中取得操作数,所以它的运行方式是基于栈而不是基于寄存器。虚拟机把操作数栈作为它的工作区,因为大多数指令都要从这里弹出数据,执行运算,然后把结果压回操作数栈。
1.2 本地方法栈

与虚拟机栈类似,不过虚拟机栈是为虚拟机执行Java方法(字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。该区域同样会报StackOverflowError 方法区

1.3 方法区

用于存储被Java虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。不同于Java堆的是,Java虚拟机规范对方法区的限制非常宽松,可以选择不实现垃圾收集(永远占据内存)。

常量池:这个名词可能大家也经常见,它是方法区的一部分。Class文件除了有类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池,用于存放编译期生成的各种字面量和符号引用。(JDK1.7已经把常量池转移到堆里面了)

1.4 堆区

所有通过new对象的内存都在对中分配;是虚拟机最大一块内存,是要GC回收的。这一部分也是重点需要分析的。

1.5 程序计数器

一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器完成。此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。(也就是说明其他区域都可能产生OOM,但是我们开发中重点是根据堆的原理避免OOM)


2.Java堆区分析

Java堆是Java虚拟机所管理的内存中最大的一块,被进程的所有线程共享,在虚拟机启动时被创建。该区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存,Java堆是垃圾收集器管理的主要区域。根据Java虚拟机规范,Java堆可以处于物理上不连续的内存空间,只要逻辑上连续即可。该区域的大小可以通过-Xmx和-Xms参数来扩展(这部分不懂),如果堆中没有内存完成实例分配,并且堆也无法扩展,将会抛出OutOfMemoryError异常。

2.1 堆区内存

由于现在的收集器基本都采用分代收集算法,所以Java堆中还可以分为老年代和新生代(Eden、From Survivor、To Survivor)

clipboard.png

(一般服务器需要修改 移动端不太需要修改)

3. 垃圾回收原理
3.1 垃圾收集算法
3.1.1 引用计数算法(jdk1.2以前)

引用计数算法只要可达 有被引用就+1 就不会被回收

图片.png

3.1.2 引用计数算法(下面几种都是jdk1.2以后)

之间的连线关系是通过引用来实现关联的。

图片.png

既然提到了引用不得不提四大引用类型:

图片.png

clipboard.png

这部分我一直没有找到比较好的文章,自己本身也理解不好。后期有机会会找找书籍与实践好好研究下另写文章。 参考1 参考2

3.2 垃圾回收算法

通过收集算法。将垃圾对象回收JVN虚拟机也是用过一些算法进行处理掉垃圾的。

3.2.1 标记-清楚算法

clipboard.png

3.2.1 复制算法

clipboard.png

3.2.1 标记整理算法

标记整理算法是对标记-清楚算法做了一些调整,当扫描到不被引用的对象的时候 它和标记-清除算法一样会移除,但是它会将所有存活的对象向左移动并更新指针 因为要移动对象并更新指针 所以成本更高,但是解决了内存碎片的问题

clipboard.png


总结 : 这三种算法是根据实际情况在虚拟机中结合使用的。并不知道单一使用 根据不同的优缺点与场景JVM会通过运算来决定使用哪种。

3.3 触发回收

clipboard.png

手动调用虚拟机也不会马上执行,它也是会等到合适的时机进行内存回收。但是调用System.gc()会增到虚拟机的压力。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.01.14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.1 Java栈
  • Java栈帧
  • 1.2 本地方法栈
  • 1.3 方法区
  • 1.4 堆区
  • 1.5 程序计数器
  • 2.Java堆区分析
    • 2.1 堆区内存
    • 3. 垃圾回收原理
      • 3.1 垃圾收集算法
        • 3.1.1 引用计数算法(jdk1.2以前)
          • 3.1.2 引用计数算法(下面几种都是jdk1.2以后)
            • 3.2 垃圾回收算法
              • 3.2.1 标记-清楚算法
                • 3.2.1 复制算法
                  • 3.2.1 标记整理算法
                    • 3.3 触发回收
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档