为了账号安全,请及时绑定邮箱和手机立即绑定

JVM学习笔记(2)---Java内存区域

标签:
Java

Java与C的内存管理区别

在C/C++中,需要使用 delete/free 等函数来手动释放内存;
而在Java中,因为Java采用了 垃圾回收机制,程序猿无需释放内存,由 虚拟机自动管理内存,会较少的出现内存泄漏和溢出的问题。
因此我们需要深入了解虚拟机是如何使用内存的,万一出现内存泄漏和溢出,也方便排查。

运行时的数据区域

webp

Java虚拟机运行时数据区

程序计数器(Program Counter Register)

程序计数器用于记录当前线程 正在执行字节码 指令地址。
计数器通过改变记录的值,来选取下一条要执行的字节码指令,循环、跳转、异常处理、线程恢复等都是通过计数器完成的。每个线程有独立的计数器,互不影响。

虚拟机栈(VM Stack)

虚拟机栈用于记录 执行Java方法
栈只保存基本数据类型的对象(byte、char、int等)和自定义对象的引用(reference类型,不是对象)
当方法执行时,虚拟机栈会创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等信息。 方法的执行过程就是一个栈帧入栈出栈的过程。

Java虚拟机规范中,对该区域规定了两种异常:

  • StackOverFlowError:线程请求的栈深度大于虚拟机允许的栈深度

  • OverOfMemoryError:动态扩展的线程无法申请到足够的内存时 (OOM常见情况

StackOverFlowError示例:通过递归不断增加栈深度,导致栈溢出

public class JVMStacksOverFlowError {
    public int stackLength = 1;    public void JVMStackOverFlowError() {
        stackLength++;
        JVMStackOverFlowError();
    }    public static void main(String[] args) throws Throwable {
        JVMStacksOverFlowError stack = new JVMStacksOverFlowError();        try {            stack.JVMStackOverFlowError();
        } catch (Throwable e) {
            System.out.println("stack length is :" + stack.stackLength);
            e.printStackTrace();
        }
    }
}

运行结果如图所示:


webp

StackOverFlowError


OutOfMemoryError示例:通过不断创建线程来分配栈内存,导致内存不够

public class JVMOutOfMemoryError {    public int threadCount = 0;    public void addNewThread() {        while (true) {
            threadCount++;            new Thread() {                @Override
                public void run() {                    while (true) ;
                }
            }.start();
        }
    }    public static void main(String[] args) throws Throwable {
        JVMOutOfMemoryError ofmeMain = new JVMOutOfMemoryError();        try {
            ofmeMain.addNewThread();
        } catch (Throwable e) {
            System.out.println("thread count is :" + ofmeMain.threadCount);
            e.printStackTrace();
        }
    }
}

运行结果如图所示:


webp

OutOfMemoryError

本地方法栈(Native Method Stack)

本地方法栈用于记录 执行Native方法
当虚拟机调用本地(native)方法时,虚拟机不会创建新的栈帧,虚拟机栈会保持不变,虚拟机只是简单的动态连接并直接调用相关的本地方法。
如果本地方法接口是c连接模型的话,它的本地方法栈就是c栈。当c程序调用一个c函数时,传递给该函数的参数以相应的顺序压入栈,它的返回值以确定的方式返回给调用方。这就是虚拟机实现中本地方法栈的行为。(本地方法栈说明)
本地方法栈也会抛出StackOverflowError和OutOfMemoryError异常。

堆(Heap)

堆用于存储 对象实例,管理 垃圾回收
堆是JVM所管理的内存中最大的一块。

webp

堆内存


根据分代收集算法,堆被分为新生代老生代
新生代:Young Generation,主要用来存放新生的对象实例。
老年代:Old Generation/Tenured Generation,主要存放应用程序声明周期长的内存对象实例。

方法区(Method Area)

方法区存储已经被虚拟机加载的类信息常量静态变量即时编译器编译后的代码等等。
参见 方法区存储信息

webp



作者:weberweber
链接:https://www.jianshu.com/p/56c9a4842cf3


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消