1、Java虚拟机之内存区域

为什么要了解JAVA内存管理?

我们知道,用JAVA进行编程,最大的优势在于内存管理。我们可以完全忽略内存管理的细节,专注于逻辑业务上。但是,并不代表它就不会出现内存溢出或泄露的问题。而且,因为JAVA有自动管理内存的机制而对这一块不了解,显然是有点low的。所以,了解一下JAVA的内存管理,既有助于提高逼格,也能让我们在进行开发的时候,可以针对内存溢出或泄露的问题进行一些优化。

JAVA运行时内存区域

JAVA虚拟机在执行JAVA程序的过程中会把它所管理的内存分为若干个不同的数据区域。这些区域都有各自的用途、创建和销毁的时间,有的是随着虚拟机进程启动而存在的,有的则依赖用户线程的启动和结束而建立和销毁的。

通过下面这张图,我们可以比较直观的看出,虚拟机划分的几个数据区域。
JAVA运行时区域

根据JAVA虚拟机规范,内存被划分为:方法区、虚拟机栈、本地方法栈、堆、程序计数器、运行时常量池(程序运行时,由方法区分配的区域,所以在图中没画出来)

  • 程序计数器(线程私有)

记载了线程中正在运行的JAVA方法的地址,如果执行的是本地方法,这个计数器则为空地址。

每个线程都有独立的程序计数器,该计数器主要是用来支持多线程的阻塞、挂起、恢复等操作。所以,这个计数器也是每个线程私有的内存区域。而且也是唯一一个JAVA虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

  • 虚拟机栈(线程私有)

虚拟机栈也是线程私有的。每个线程创建的同时跟着一起创建的,用于存储栈桢。

每个方法在执行时都会创建一个栈桢,用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

在JAVA虚拟机规范中,这个区域规定了两种异常情况:
1. 线程请求的栈深度大于虚拟机运行深度,抛出StackOverFlowError异常;
2. 虚拟机栈可动态拓展时,没有申请到足够内存,抛出OutOfMemoryError异常。

  • 本地方法栈(线程私有)

与虚拟机栈类似,也是线程私有的。它是用来支持Native方法的执行的。在虚拟机规范中,对本地方法栈中的方法使用的语言、使用方法、数据结构都没有强制规定,可以自由实现它。和虚拟机栈一样,也会抛出StackOverFlowError异常和OutOfMemoryError异常。

  • 堆(全局共享的)

用于存储对象实例及数组的。这个区域也是垃圾收集器(GC)的主要管理区域。为了方便内存回收,该区域还会进行很多划分,不变的是,存放的内容都是对象实例。该区域的大小可以通过-Xmx和-Xms来控制。如果没有内存可给实例分配,且无法拓展时,会抛出OutOfMemoryError异常。

  • 方法区(全局共享的)

用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。

在JAVA虚拟机规范中,没有强制要求实现这部分的内存管理。垃圾收集行为在这部分也比较少。当方法区无法满足内存分配需求时,会抛出OutOfMemoryError异常。

内存的管理其实就是内存分配和内存回收。而内存分配的几个区域可以分为两类,程序计数器、本地方法栈、虚拟机栈这几个区域是属于线程私有的,随着线程创建而创建,销毁而销毁,销毁时内存也会释放掉,所以这几个区域是不需要进行GC的。方法区因为它的定义GC行为相对会比较少,所以,堆则成为了垃圾回收器的重点维护对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值