Java与C的内存管理区别
在C/C++中,需要使用 delete/free 等函数来手动释放内存;
而在Java中,因为Java采用了 垃圾回收机制,程序猿无需释放内存,由 虚拟机自动管理内存,会较少的出现内存泄漏和溢出的问题。
因此我们需要深入了解虚拟机是如何使用内存的,万一出现内存泄漏和溢出,也方便排查。
运行时的数据区域
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(); } } }
运行结果如图所示:
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(); } } }
运行结果如图所示:
OutOfMemoryError
本地方法栈(Native Method Stack)
本地方法栈用于记录 执行 的 Native方法。
当虚拟机调用本地(native)方法时,虚拟机不会创建新的栈帧,虚拟机栈会保持不变,虚拟机只是简单的动态连接并直接调用相关的本地方法。
如果本地方法接口是c连接模型的话,它的本地方法栈就是c栈。当c程序调用一个c函数时,传递给该函数的参数以相应的顺序压入栈,它的返回值以确定的方式返回给调用方。这就是虚拟机实现中本地方法栈的行为。(本地方法栈说明)
本地方法栈也会抛出StackOverflowError和OutOfMemoryError异常。
堆(Heap)
堆用于存储 对象实例,管理 垃圾回收。
堆是JVM所管理的内存中最大的一块。
堆内存
根据分代收集算法,堆被分为新生代和老生代。
新生代:Young Generation,主要用来存放新生的对象实例。
老年代:Old Generation/Tenured Generation,主要存放应用程序声明周期长的内存对象实例。
方法区(Method Area)
方法区存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等等。
参见 方法区存储信息
作者:weberweber
链接:https://www.jianshu.com/p/56c9a4842cf3
共同学习,写下你的评论
评论加载中...
作者其他优质文章