刚刚我们说了为什么要回收垃圾,和什么是OOM那么我们下面就给大家介绍,我们JVM中什么地方需要进行垃圾回收。
java堆是GC垃圾回收的主要区域。 GC分为两种: Minor GC、Full GC(也叫做Major GC).
Java虚拟机(JVM)是一种在计算机上运行的虚拟机,它负责将Java字节码转换为可执行代码。在这个过程中,JVM需要管理内存空间,其中包括堆空间和栈空间。
----------------------------------------------------------------
类加载器 App类加载器 扩展类加载器 根类加载器 package java.lang.String; public class String{ public static void main(String args[]){ String s = new String(); } } // 双亲委派机制,安全机制,防止 // 自定义String 希望能够覆盖源码String 但是类加载的时候,app类加载器--》扩展类加载器---》根类加载器,跟类加载器会调用源码的Stri
Java虚拟机栈是线程私有的,没有数据安全问题,而堆相比较于Java虚拟机栈而言更为复杂。
JVM运行时内存组成分为一些线程私有的,其他的是线程共享的。 线程私有 程序计数器:当前线程所执行的字节码的行号指示器。 Java虚拟机栈:java方法执行的内存模型,每个方法被执行时都会创建一个栈帧,存储局部变量表,操作栈,动态链接,方法出口等信息。每个线程都有自己独立的栈空间,线程栈只存储基本类型和对象地址,方法中局部变量存放在线程空间中。 本地方法栈:Native方法服务,在hotspot虚拟机中和java虚拟机栈合二为一。 线程共享 java堆:存放对象实力,几乎所有的对象实例及其属性都在这里分
我们先来回忆一下JVM系列1的文章中有提到,方法区存储每个类的结构,比如:运行时常量池、属性和方法数据,以及方法和构造函数等数据。所以我们这个obj1是存在方法区的,而new会创建一个对象实例,对象实例是存储在堆内的,于是就有了下面这幅图(方法区指向堆):
jvm既 Java Virtual Machine,既然是虚拟机,其必有存储空间,且不同的存储空间,存储特定的数据,如图所示:
给大家分享一下,面试官经常问的刁钻问题,new Object()到底占用几个字节?
上一篇文章简单介绍了一下jvm的几个概念。接下来这篇文章将跟大家探讨一下JVM的工作原理。
看到这张图的同学,千万不要到处分享。我们仅限于小范围讨论,因为这张图威力很大,是我花了10年时间才画出来的!
在JVM中,堆区是重中之重。通过前面文章的学习,我们知道了,栈区是不会有垃圾回收的,所以,经常说的垃圾回收,其实就是回收的是堆区的数据。在这里,我们将会看到传说中的,新生代、老年代、永久代(元空间)。凯哥Java(kaigejava)欢迎大家一起学习。
通常我们都知道在堆空间新生代Eden区满了,会触发minor GC, 在老年代满了会触发full GC, 触发full GC会导致Stop The World, 那你们知道还有一个区域满了一会触发Full GC么?而且这个区域满了会直接影响我们的开发效率。
垃圾回收机制是如何实现的呢?其实从Jvm内存模型中入手对于理解GC会有很大的帮助,不过这里只需要了解一个大概,说多了反而混淆视线。
堆内存变大后,虽然垃圾收集的频率减少了,但每次垃圾回收的时间变长。 如果堆内存为 14 G,那么每次 Full GC 将长达数十秒。如果 Full GC 频繁发生,那么对于一个网站来说是无法忍受的。
-它是虚构出来的计算机,是通过实际的计算机仿真模拟各种计算机功能来实现的 JVM包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个储存方法域。它屏蔽了与具体操作系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在各种平台上不加修改的运行。JVM在执行字节码时最终还是把字节码转换成具体平台上的机器指令执行。
做Java的大都没有c++ 的那种分配内存的烦恼,因为Java 帮我们管理内存,但是这并不代表我们不需要了解Java的内存结构,因为线上经常出现内存的问题,今天聊一下内存的问题。
主要保证 GC 的时候扫描高效。由于 TLAB 仅线程内知道哪些被分配了,在 GC 扫描发生时返回 Eden 区,如果不填充的话,外部并不知道哪一部分被使用哪一部分没有,需要做额外的检查,如果填充已经确认会被回收的对象,也就是 dummy object, GC 会直接标记之后跳过这块内存,增加扫描效率。反正这块内存已经属于 TLAB,其他线程在下次扫描结束前是无法使用的。这个 dummy object 就是 int 数组。为了一定能有填充 dummy object 的空间,一般 TLAB 大小都会预留一个 dummy object 的 header 的空间,也是一个 int[] 的 header,所以 TLAB 的大小不能超过int 数组的最大大小,否则无法用 dummy object 填满未使用的空间。
为什么划分老年代和新生代,主要对象大小不一样,对象生命周期不一样。划分后,提供垃圾回收效率,节省资源,提升对象利用率等等。
堆针对一个JVM进程来说是唯一的,也就是一个进程只有一个JVM,但是进程包含多个线程,他们是共享同一堆空间的。
学习笔记摘自https://www.bilibili.com/video/av30023103/?p=67 内存管理 java的内存管理很大程度指的就是对象的管理,其中包括对象空间的分配和释放。 对象
G1将Java堆分成多个分区。分区的大小可以依据堆的尺寸而改变,但必须是2的幂,同时最小为1MB,最大为32MB。由此得出可能的分区尺寸是1 MB、2MB、4 MB、8 MB、16 MB和32MB。所有分区的大小都一样,在JVM运行过程中它们的尺寸也不会发生变化。分区尺寸是基于Java堆内存的初始值和最大值的平均数来进行计算的,这样对于这个平均堆尺寸就会有2000个左右的分区。举个例子,对一个16G的Java堆使用-Xmx16g -Xms16g命令行选项,G1就会选择采用16GB/2000 = 8MB的分区尺寸。
java堆也是线程共享的区域,我们的类的实例就放在这个区域,可以想象你的一个系统会产生很多实例,因此java堆的空间也是最大的。如果java堆空间不足了,程序会抛出OutOfMemoryError异常。
注意右下角区域,红框部分。这块内存是什么呢?非堆!那么,左边是代码缓存区内存,右边红框就是字符串池,常量,基本类型数据的内存区。然后呢?已经满了。什么原因呢?
JVM通过类加载机制,把class文件装载进JVM中,然后JVM解析class文件的内容,于是就有了类加载过中的链接、初始化等。
线程共享的运行时内存区域,它存储了每一个类的结构信息。什么叫类的结构信息,其实就是上一篇讲类加载器时说的类的模板。也就是类的属性、构造器、方法、常量池等。而且,方法区是一种规范,不是具体实现。java7及以前的实现叫永久代,java8开始,方法区的实现叫元空间。
JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
其中虚拟机栈、程序计数器、本地方法栈是线程私有的,也就是说每个线程都会维护自己的一份虚拟机栈、程序计数器、本地方法栈,而方法区和堆是所有线程共享的。
java虚拟机在应用在执行的过程中将自己管理的内存分为5部分: 方法区,堆,虚拟机栈,本地方法栈,程序计数器
e.printStackTrace() 会导致锁死?这仅仅是打印啊,怎么可能?!
注意右下角区域,红框部分。这块内存是什么呢?非堆!那么,左边是代码缓存区内存,右边红框就是字符串池,常量,基本类型数据的内存区。然后呢?已经满了。什么原因呢?e.printStackTrace()!
非堆!那么,左边是代码缓存区内存,右边红框就是字符串池,常量,基本类型数据的内存区。
原文链接:https://my.oschina.net/sxgkwei/blog/825700
对于常见的GC算法,我们都应该知道,例如:标记清除算法、复制算法、标记整理算法等。标记清除算法由于回收之后存在大量的内存碎片,存在效率和空间问题!为了解决效率问题,引出了复制算法!熟悉GC算法的小伙伴应该都看过周志明老师的《深入理解Java虚拟机》这本书。因此,这里不再讨论这几种GC算法的区别,这里假设大家都已经有所了解,为了照顾遗忘的小伙伴,这里祭出周志明老师的部分文章内容,没有了解的赶紧下来补习一下!以下来自该书的截图:(注:这里只做交流学习使用!如需阅读请购买正版!)
垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了。 jvm 中,程序计数器、虚拟机栈、本地方法栈都是随线程而生随线程而灭,栈帧随着方法的进入和退出做入栈和出栈操作,实现了自动的内存清理,因此,我们的内存垃圾回收主要集中于 java 堆和方法区中,在程序运行期间,这部分内存的分配和使用都是动态的。
最近很多人都在面试,都在问如何快速复习JVM,本文就采用文字+图的形式来解说JVM,希望对你有所帮助。
OutOfMemoryError 异常应该可以算得上是一个非常棘手的问题。JAVA 的程序员不用像苦逼的 C 语言程序员手动地管理内存,JVM 帮助他们分配内存,释放内存。但是当遇到内存相关的问题,就比如 OutOfMemoryError,如何去排查并且解决就变成一个非常令人头疼的问题。在 JAVA 中,所有的对象都存储在堆中,通常如果 JVM 无法再分配新的内存,内存耗尽,并且垃圾回收器无法及时回收内存,就会抛出 OutOfMemoryError。
Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再需要考虑内存管理。由于有个垃圾回收机制,Java中的对象不再有“作用域”的概念,只有对象的引用才有“作用域”。垃圾回收可以有效的防止内存泄露,有效的使用空闲的内存。
JDK 1.8 同 JDK 1.7 比,最大的差别就是:元数据区取代了永久代。元空间的本质和永久代类似,都是对 JVM 规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元数据空间并不在虚拟机中,而是使用本地内存。
比较古老的回收算法。原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为0的对象。此算法最致命的是无法处理循环引用的问题。
Java 堆从 GC 的角度还可以细分为: 新生代(Eden 区、From Survivor 区和 To Survivor 区)和老年代。
在标记阶段首先通过根节点(GC Roots),标记所有从根节点开始的对象,未被标记的对象就是未被引用的垃圾对象。然后,在清除阶段,清除所有未被标记的对象。
堆是在 JVM 启动时创建的,主要用来维护运行时数据,如运行过程中创建的对象和数组都是基于这块内存空间。Java 堆是非常重要的元素,如果我们动态创建的对象没有得到及时回收,持续堆积,最后会导致堆空间被占满,内存溢出。
领取专属 10元无门槛券
手把手带您无忧上云