不好意思!耽误你的十分钟,JVM内存布局还给你

简介: 先赞后看,南哥助你Java进阶一大半在2006年加州旧金山的JavaOne大会上,一个由顶级Java开发者组成的周年性研讨会,公司突然宣布将开放Java的源代码。于是,下一年顶级项目OpenJDK诞生。Java生态发展被打开了新的大门,Java 7的G1垃圾回收器、Java 8的Lambda表达式和流API…大家好,我是南哥。一个Java学习与进阶的领路人,相信对你通关面试、拿下Offer进入心心念念的公司有所帮助。

先赞后看,南哥助你Java进阶一大半

在2006年加州旧金山的JavaOne大会上,一个由顶级Java开发者组成的周年性研讨会,Sun Microsystems公司突然宣布将开放Java的源代码。于是,下一年顶级项目OpenJDK诞生。

Java生态发展被打开了新的大门,Java 7的G1垃圾回收器、Java 8的Lambda表达式和流API...

在这里插入图片描述

大家好,我是南哥。

一个Java学习与进阶的领路人,相信对你通关面试、拿下Offer进入心心念念的公司有所帮助。

⭐⭐⭐本文收录在全网独一份的《JavaSouth》:https://github.com/hdgaadd/JavaSouth

1. JVM内存布局

1.1 堆内存

我们Java程序员相对C语言老哥来说,南友们不需要写内存管理这些东西。具体什么东西呢?不需要为每个对象去写繁琐的释放内存代码。

以下是一个C语言示例,C语言需要显式地使用free函数来释放内存。

#include <stdio.h>
#include <stdlib.h>

int main() {
   
   
    // 分配内存以存储一个整数
    int *ptr = malloc(sizeof(int));
    if (ptr == NULL) {
   
   
        printf("内存分配失败\n");
        return 1;
    }
    // 使用分配的内存
    *ptr = 123;
    printf("存储的整数是: %d\n", *ptr);

    // 完成使用后释放内存
    free(ptr);
    return 0;
}

我们把重要的内存管理最高权力交给了JVM虚拟机,总得多多了解JVM虚拟机是如何处理内存管理的、包括JVM内存区域包含了什么,否则线上出了什么故障,不了解原理连解决的思路都没有。

JVM内存布局包含了五部分,分别是堆内存、本地方法栈、虚拟机栈、方法区、程序计数器。南哥画画图,给你加深理解。

在这里插入图片描述

堆内存的作用很方便记忆,它的唯一目的就是存放对象实例。成员变量的变量值无论是基本类型、还是引用类型都存储在堆内存中,而局部变量的变量值如果是引用类型则存储在堆内存中。这点下文南哥会继续讲到。

public class JavaSouth {
   
   

    // 成员变量:无论是基本类型、还是引用类型都存储在堆内存中
    private int memberInt = 10;
    // 成员变量:无论是基本类型、还是引用类型都存储在堆内存中
    private String memberString = "Hello, World!";

    public void displayInfo() {
   
   
        // 局部变量:如果是引用类型则存储在堆内存中
        String localString = new String("Local String");

        System.out.println("Member int: " + memberInt);
        System.out.println("Member String: " + memberString);
        System.out.println("Local String: " + localString);
    }
}

JVM的堆内存,在国内也被称为GC堆。说到GC回收,目前主流垃圾回收器都使用了分代收集算法,GC堆被分为了新生代、老年代。

新生代、老年代又使用了不同的垃圾回收算法,如新生代的对象特点就是存活时间短,更适合把内存一分为二的复制算法;而老年代的对象存活时间就相对较长了,各种大对象、小对象也比较复杂,可以使用标记清除算法、标记整理算法。这些南哥在JVM垃圾回收章节有提到过。

1.2 虚拟机栈

虚拟机栈是和Java中的方法相关的,因为每个方法在被一个线程执行时,都会去创建一个栈帧,因此虚拟机栈的生命周期也和线程相同,虚拟机栈也属于线程私有。

虚拟机栈的栈帧包含了这么些东西:局部变量表、操作数栈、动态链接、方法返回地址。难记吧?南哥是这么觉得。

Oracle官方文档中,我们可以了解到虚拟机栈一共会报出StackOverflowErrorOutOfMemoryError两个异常。

  • If the computation in a thread requires a larger Java Virtual Machine stack than is permitted, the Java Virtual Machine throws a StackOverflowError.
  • If Java Virtual Machine stacks can be dynamically expanded, and expansion is attempted but insufficient memory can be made available to effect the expansion, or if insufficient memory can be made available to create the initial Java Virtual Machine stack for a new thread, the Java Virtual Machine throws an OutOfMemoryError.

翻译过来。

  • 如果线程中的计算需要比允许值更大的 Java 虚拟机堆栈,则 Java 虚拟机将抛出StackOverflowError,也就是堆栈溢出。
  • 如果 Java 虚拟机堆栈可以动态扩展,并且尝试扩展但没有足够的内存来实现扩展,或者没有足够的内存来为新线程创建新的初始 Java 虚拟机堆栈,则 Java 虚拟机将抛出OutOfMemoryError,也就是内存溢出。

1.3 本地方法栈

本地方法栈和虚拟机栈的作用相差不大,都是为方法的运行提供一个栈帧。众所周知Java很多关于数学计算、系统调用等操作,都利用了C语言的本地方法,这些本地方法也叫Native方法。

南哥给一段由C语言实现的Native方法代码。

下面是String类的intern方法,该方法使用的便是本地方法。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
   
   
    /**
     * 返回字符串对象的规范表示。
     */
    public native String intern();
}

1.4 方法区

上文跟着南哥我们知道虚拟机栈、本地方法栈提供栈帧,而堆内存提供内存区域。其实方法区也起到提供一个内存区域的作用,方法区存放了类相关的数据:类结构信息、常量、静态变量等。

Oracle官方文档中,我们可以知道方法区会出现OutOfMemoryError异常。

If memory in the method area cannot be made available to satisfy an allocation request, the Java Virtual Machine throws an OutOfMemoryError.

如果方法区中的内存不足以满足分配请求,则 Java 虚拟机将抛出OutOfMemoryError

1.5 程序计数器

程序计数器的主要作用是存储指向当前线程正在执行的JVM指令的地址。

而程序计数器在整个JVM内存布局中,是唯一一个不会出现OutOfMemoryError的区域。

1.6 变量存储位置

南哥在上文有提到堆内存、方法区具体存放了什么内容,现在我们整理整理Java各种变量的变量名、变量值所存储的位置。

这一点,面试官考得细的话会考到。

  1. 成员变量
    • 变量名作为类的一部分,其结构定义存储在方法区
    • 而变量值无论是基本数据类型还是引用类型,都是存储在堆内存中的对象实例内。
  2. 类变量
    • 变量名作为类的一部分,其结构定义也存储在方法区
    • 变量值无论是基本数据类型还是引用类型,都存储在方法区中,因为它们属于类级别的数据。
  3. 局部变量
    • 局部变量是存在于方法中的变量,变量名存储在虚拟机栈的栈帧中。
    • 而变量值如果是基本数据类型,存储在虚拟机栈的栈帧中;如果是引用类型,变量值存储在中,但引用所指向的对象本身存储在堆内存中。

戳这,《JavaSouth》作为一份涵盖Java程序员所需掌握核心知识、面试重点的《Java学习进阶指南》。

在这里插入图片描述

我是南哥,南就南在Get到你的有趣评论➕点赞➕关注。

创作不易,不妨点赞、收藏、关注支持一下,各位的支持就是我创作的最大动力❤️

相关文章
|
1月前
|
存储 安全 Java
jvm 锁的 膨胀过程?锁内存怎么变化的
【10月更文挑战第3天】在Java虚拟机(JVM)中,`synchronized`关键字用于实现同步,确保多个线程在访问共享资源时的一致性和线程安全。JVM对`synchronized`进行了优化,以适应不同的竞争场景,这种优化主要体现在锁的膨胀过程,即从偏向锁到轻量级锁,再到重量级锁的转变。下面我们将详细介绍这一过程以及锁在内存中的变化。
37 4
|
4天前
|
Arthas 监控 Java
JVM进阶调优系列(9)大厂面试官:内存溢出几种?能否现场演示一下?| 面试就那点事
本文介绍了JVM内存溢出(OOM)的四种类型:堆内存、栈内存、元数据区和直接内存溢出。每种类型通过示例代码演示了如何触发OOM,并分析了其原因。文章还提供了如何使用JVM命令工具(如jmap、jhat、GCeasy、Arthas等)分析和定位内存溢出问题的方法。最后,强调了合理设置JVM参数和及时回收内存的重要性。
|
2天前
|
Java Linux Windows
JVM内存
首先JVM内存限制于实际的最大物理内存,假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制。
6 1
|
1月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
55 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
1月前
|
存储 缓存 算法
JVM核心知识点整理(内存模型),收藏再看!
JVM核心知识点整理(内存模型),收藏再看!
JVM核心知识点整理(内存模型),收藏再看!
|
21天前
|
存储 算法 Java
聊聊jvm的内存结构, 以及各种结构的作用
【10月更文挑战第27天】JVM(Java虚拟机)的内存结构主要包括程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区和运行时常量池。各部分协同工作,为Java程序提供高效稳定的内存管理和运行环境,确保程序的正常执行、数据存储和资源利用。
45 10
|
20天前
|
存储 算法 Java
Java虚拟机(JVM)的内存管理与性能优化
本文深入探讨了Java虚拟机(JVM)的内存管理机制,包括堆、栈、方法区等关键区域的功能与作用。通过分析垃圾回收算法和调优策略,旨在帮助开发者理解如何有效提升Java应用的性能。文章采用通俗易懂的语言,结合具体实例,使读者能够轻松掌握复杂的内存管理概念,并应用于实际开发中。
|
30天前
|
存储 监控 算法
JVM调优深度剖析:内存模型、垃圾收集、工具与实战
【10月更文挑战第9天】在Java开发领域,Java虚拟机(JVM)的性能调优是构建高性能、高并发系统不可或缺的一部分。作为一名资深架构师,深入理解JVM的内存模型、垃圾收集机制、调优工具及其实现原理,对于提升系统的整体性能和稳定性至关重要。本文将深入探讨这些内容,并提供针对单机几十万并发系统的JVM调优策略和Java代码示例。
46 2
|
1月前
|
存储 Java
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
这篇文章详细地介绍了Java对象的创建过程、内存布局、对象头的MarkWord、对象的定位方式以及对象的分配策略,并深入探讨了happens-before原则以确保多线程环境下的正确同步。
51 0
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
|
1月前
|
Java API 对象存储
JVM进阶调优系列(2)字节面试:JVM内存区域怎么划分,分别有什么用?
本文详细解析了JVM类加载过程的关键步骤,包括加载验证、准备、解析和初始化等阶段,并介绍了元数据区、程序计数器、虚拟机栈、堆内存及本地方法栈的作用。通过本文,读者可以深入了解JVM的工作原理,理解类加载器的类型及其机制,并掌握类加载过程中各阶段的具体操作。