深入理解Java内存工作原理

开发
在Java中,JVM(Java虚拟机)负责自动管理内存,用于存储变量、类、字段等等。JVM将内存划分为两个区域,分别是栈(Stack)和堆(Heap)。

在Java中,JVM(Java虚拟机)负责自动管理内存,用于存储变量、类、字段等等。JVM将内存划分为两个区域,分别是栈(Stack)和堆(Heap)。

什么是栈

在JVM中,栈是一种高效的内存管理方式,每个线程都有自己的栈区域。栈采用堆叠的方式,将实例化的字段依次添加到内存中。不过,栈的大小是有限的,所以无法存储整个对象。因此,原始类型和对象指针可以直接存储在栈中,而不是整个对象。栈的名字就像它的功能一样,只是一个堆叠的空间,无法容纳大型对象。

当需要移除对象时,我们需要按照堆叠的顺序逐个移除,即先移除最先添加的对象。这是因为数据在堆叠时,后添加的对象会放在先添加的对象的上方,如果不移除这些对象,就无法到达底部。简而言之,要想取出底部的对象,必须先移除位于其上方的对象。

什么是堆

从GIF动画中可以看到,堆的大小比栈要大,因为堆是存储对象的主要区域。每个创建的对象都存储在堆中,而对象的引用则存储在栈中。这种设计方式使得栈和堆之间建立了关联,通过栈中的引用可以访问和操作堆中的对象。如下所示:

 public List<String> test() {
    String newString = "test";
    List<String> testList = new ArrayList<>();
    testList.add(newString);
    return testList;
  }

与之相反,应用程序只有一个堆。这个设计是合理的,因为我们可能需要在方法之间传递多个大型对象。栈主要用于存储局部变量,可能会有多个栈存在,但它们都共享同一个堆来存储对象。具体来说,对象的指针存储在栈中。因此,当我们需要在方法之间传递对象时,不会在栈中复制整个对象,而是传递对象的引用。这种方式既高效又节省内存空间。

此外,堆实际上并不是一个固定的单一区域。如果你放大查看堆,你会看到4个不同的区域。

它们被称为代(Generation)。堆建立在两个主要代上,一个是年轻代(Young Generation),另一个是老年代(Old Generation)。年轻代又被分为三个空间,分别是Eden、Survivor 0和Survivor 1。当你学到它们的作用时,会更清楚。创建的对象首先放置在Eden空间中,然后当Eden空间满时,对象会被移动到Survivor 0或Survivor 1。之后,创建的对象再次放置在Eden中。当Eden再次满时,Eden和Survivor 0或1将被移动到Survivor 0或1。如果对象被移动超过五次,那么这些对象将被放置在老年代中。这意味着,现在这些对象是需要的,并且将存活在老年代中,除非失去了其引用。如果栈中没有持有其引用的变量,这意味着该对象符合垃圾回收的条件。最后一个对性能问题非常重要,因此我们需要了解Java内存如何工作才能理解它。

Metaspace

除了之前提到的栈和堆区域外,内存中还有另一个区域,即Metaspace。Metaspace是存储应用程序元数据的区域,它承担着重要的任务。通常情况下,我们不需要深入了解Metaspace内部情况。Metaspace还有一个重要的功能,就是存储静态变量、方法和类。这也解释了为什么静态关键字可以从任何地方访问,因为它们的存储位置就在Metaspace中,这样每个线程都可以方便地进行访问。Metaspace的存在为我们提供了便利,使得静态元素的访问变得更加方便。

JVM启动参数中的常用标志

可以通过设置一些标志来告诉JVM要执行的操作。以下是一些标志的示例:

  • XmsNg 设置初始大小
  • XmxNg 设置最大大小
  • XX:NewRatio=N 年轻代与老年代的比例
  • XX:NewSize=N 年轻代的初始大小
  • XX:MaxNewSize=N 年轻代的最大大小
责任编辑:赵宁宁 来源: Java学研大本营
相关推荐

2020-11-04 15:35:13

Golang内存程序员

2021-09-08 06:51:52

AndroidRetrofit原理

2022-07-06 08:05:52

Java对象JVM

2020-08-10 18:03:54

Cache存储器CPU

2024-04-15 00:00:00

技术Attention架构

2023-11-05 12:05:35

JVM内存

2024-03-12 00:00:00

Sora技术数据

2022-09-05 08:39:04

kubernetesk8s

2021-03-10 10:55:51

SpringJava代码

2022-11-04 09:43:05

Java线程

2013-06-20 10:25:56

2015-03-24 13:28:52

Java Java Strin内存模型

2022-06-22 08:02:11

CPU操作系统Java

2019-07-01 13:34:22

vue系统数据

2023-10-13 13:30:00

MySQL锁机制

2020-03-17 08:36:22

数据库存储Mysql

2022-09-05 22:22:00

Stream操作对象

2020-03-26 16:40:07

MySQL索引数据库

2022-01-14 12:28:18

架构OpenFeign远程

2022-09-26 08:01:31

线程LIFO操作方式
点赞
收藏

51CTO技术栈公众号