专注Java教育14年 全国咨询/投诉热线:444-1124-454
赢咖4LOGO图
始于2009,口口相传的Java黄埔军校
首页 学习攻略 Java学习 深入理解Java内存模型

深入理解Java内存模型

更新时间:2022-11-17 12:21:44 来源:赢咖4 浏览783次

了解 Java 内存模型是开发、部署、监视、测试和调优 Java 应用程序性能的严肃 Java 开发人员的基本学习内容。在这篇博文中,我们将讨论 Java 内存模型以及 JVM 内存模型的每个部分如何有助于运行我们的程序。

首先看看你是否看懂下面这张JVM架构图。

JVM内存模型

在运行资源密集型 Java 程序时,您必须使用以下一些 JVM 内存配置。

-XmsSetting — 初始堆大小

-XmxSetting — 最大堆大小

-XX:NewSizeSetting — 新一代堆大小

-XX:MaxNewSizeSetting — 最大新生代堆大小

-XX:MaxPermGenSetting — 永久代的最大大小

-XX:SurvivorRatioSetting — 新的堆大小比率(例如,如果 Young Gen 大小为 10m 且内存开关为 –XX:SurvivorRatio=2,则将为 Eden 空间保留 5m,为两个 Survivor 空间各保留 2.5m,默认值 = 8)

-XX:NewRatio — 提供 Old/New Gen 大小的比率(默认值 = 2)

但是你有没有想过你的 JVM 是如何驻留在内存中的?让我展示一下。就像任何其他软件一样,JVM 会消耗主机操作系统内存上的可用空间。

然而,在 JVM 内部,存在单独的内存空间(Heap、Non-Heap、Cache),用于存储运行时数据和编译后的代码。

1.堆内存

堆分为两部分——年轻一代和老一辈

堆在 JVM 启动时分配(初始大小:-Xms)

堆大小在应用程序运行时增加/减少

最大尺寸:-Xmx

(1)年轻一代

这是为包含新分配的对象而保留的

Young Gen包括三个部分——Eden Memory和两个Survivor Memory空间(S0,S1)

大多数新创建的对象进入伊甸园空间。

当 Eden 空间充满对象时,将执行Minor GC(又名Young Collection),并将所有幸存者对象移动到其中一个幸存者空间。

Minor GC 还会检查幸存者对象并将它们移动到其他幸存者空间。所以在某个时候,其中一个幸存者空间总是空的。

经过多次 GC 循环后幸存下来的对象将被移至老年代内存空间。通常这是通过在年轻代对象有资格提升到老年代之前设置年龄阈值来完成的。

(2)老一代

这是保留的,用于包含在多轮 Minor GC 后可以存活的长寿命对象

当 Old Gen 空间已满时,执行Major GC(又名Old Collection)(通常需要更长的时间)

2.非堆内存

这包括永久生成(自 Java 8 起由元空间取代)

Perm Gen 存储每个类的结构,例如运行时常量池、字段和方法数据、方法和构造函数的代码,以及 interned 字符串

Its size can be changed using -XX:PermSize and -XX:MaxPermSize

3.高速缓存

这包括代码缓存

存放JIT编译器生成的编译代码(即native代码)、JVM内部结构、加载的profiler agent代码和数据等。

当代码缓存超过阈值时,它会被刷新(对象不会被 GC 重新定位)。

堆栈与堆

到目前为止,我没有提到任何关于 Java Stack 内存的内容,因为我想单独强调它的区别。首先,看看下面的图片,看看你是否知道这里发生了什么。

总之,长话短说,Java Stack 内存用于线程的执行,它包含方法特定的值和对 Heap 中其他对象的引用。让我们将 Stack 和 Heap 都放到一个表中,看看它们的区别。

这是一个很好的例子(来自 baeldung.com),它说明了 Stack 和 Heap 如何有助于执行一个简单的程序(使用代码检查堆栈顺序)。

类人 { 
    int pid; 
    字符串名称;
// 构造函数,setter/getter 
}
public class Driver { 
    public static void main(String[] args) { 
        int id = 23; 
        String pName = "乔恩"; 
        人 p = null;
        p = new Person(id, pName); 
    } 
}

修改

上面的 Java 内存模型是最常讨论的实现。然而,最新的 JVM 版本有不同的修改,例如引入了以下新的内存空间。

Keep Area——新生代中的一个新内存空间,用于包含最近分配的对象。直到下一个年轻一代才会执行 GC。这个区域防止对象仅仅因为它们是在年轻收集开始之前分配的而被提升。

Metaspace——从 Java 8 开始,Permanent Generation 被 Metaspace 取代。它可以自动增加它的大小(直到底层操作系统提供的大小),即使 Perm Gen 总是有一个固定的最大大小。只要类加载器处于活动状态,元数据就会在元空间中保持活动状态并且不能被释放。

注意: 始终建议您浏览供应商文档以找出适合您的 JVM 版本的内容。

内存相关问题

当存在严重的内存问题时,JVM 会崩溃并在您的程序输出中抛出错误指示,如下所示。

java.lang.StackOverFlowError — 表示Java堆栈内存已满

java.lang.OutOfMemoryError: Java heap space — 表示堆内存已满

java.lang.OutOfMemoryError: GC Overhead limit exceeded — 表示 GC 已达到其开销限制

java.lang.OutOfMemoryError: Permgen space — 表示永久代空间已满

java.lang.OutOfMemoryError: Metaspace — 表示元空间已满(自 Java 8 起)

java.lang.OutOfMemoryError: Unable to create new native thread — 表示 JVM 本机代码无法再从底层操作系统创建新的本机线程,因为已经创建了太多线程并且它们消耗了 JVM 的所有可用内存

java.lang.OutOfMemoryError: request size bytes for reason — 表示交换内存空间已被应用程序完全消耗

java.lang.OutOfMemoryError: Requested array size exceeds VM limit – 表示我们的应用程序使用的数组大小超过了底层平台允许的大小

提交申请后,顾问老师会电话与您沟通安排学习

免费课程推荐 >>
技术文档推荐 >>