草庐IT

JVM

蓝色猫猫 2023-03-28 原文

内存区域

程序计数器、虚拟机栈、本地方法栈这三个是线程私有的;堆、方法区是线程公有的;

程序计数器:记录线程走到字节码的哪一行;

虚拟机栈:由栈帧组成,每个栈帧包含局部变量表、操作数栈、动态链接、方法返回地址,当执行到一个方法的时候,就会把这个方法以栈帧形式压入栈

本地方法栈:与虚拟机栈差不多,只不过这个栈是给本地方法用的

堆:堆的垃圾回收算法常用的是分代回收法,所以堆被划分出新生代,老年代;

方法区: 1.7之前方法区的实现是永久代,会存储已被虚拟机加载的 类信息、字段信息、方法信息、常量、静态变量、即时编译器编译后的代码缓存等数据。****1.8之后方法区的实现变成了元空间,字符串常量池和静态变量等移出到堆内存中,其余的(主要是类型信息)被移到了元空间中。

元空间和永久代的区别就在于永久代会受JVM的总空间大小的限制,而元空间受限制的是内存的总大小。

常量池:常量池中主要存放两类数据,一是字面量、二是符号引用。

字面量:比如String类型的字符串值或者定义为final类型的常量的值。
符号引用:
1.类或接口的全限定名(包括他的父类和所实现的接口)
2.变量或方法的名称
3.变量或方法的描述信息
4.this

当类的字节码被加载到内存中后,他的常量池信息就会集中放入到一块内存,这块内存就称为运行时常量池,并且把里面的符号地址变为真实地址。

垃圾回收

判断对象是否能够回收有两个办法:引用计数法可达性分析

垃圾收集的算法:标记-清除、标记-整理、标记-复制、分代回收法

分代回收法

在内存中,分为新生代,老年代,永久代;这里的永久代也有叫方法区。新生代又分为Eden区,S0区,和S1区。一个对象创建,存储在Eden区,当Eden区满了,就会触发Minor GC,存活的对象将进入S0区,S0区满了之后会触发Minor GC,清空S0区内存,将存活的对象复制到S1区;S1满了也是GC清空到S0。倒来倒去,当次数达到16(可改)次时,会进入老年代;老年代满了会触发Full GC(会stop the world)。再满就会OOM了。

Full GC用的一般是标记整理和标记清除算法,所以不会转移,而Minor GC一般用的是标记-复制算法,所以会转移来转移去,同理,如果对象太大,会直接进老年代。

类加载过程

  • 加载:
  1. 通过全类名获取定义此类的二进制字节流
  2. 将字节流所代表的静态存储结构转换为方法区的运行时数据结构
  3. 在内存中生成一个代表该类的 Class 对象,作为方法区这些数据的访问入口
  • 验证:

验证文件格式、元数据、符号引用、字节码

  • 准备:

准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,会给类变量一个默认值,不对成员变量做内存分配。

从概念上讲,类变量所使用的内存都应当在方法区中进行分配。不过有一点需要注意的是:JDK 7 之前,HotSpot 使用永久代来实现方法区的时候,实现是完全符合这种逻辑概念的。 而在 JDK 7 及之后,HotSpot 已经把原本放在永久代的字符串常量池、静态变量等移动到堆中,这个时候类变量则会随着 Class 对象一起存放在 Java 堆中。

  • 解析:

解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,也就是得到类或者字段、方法在内存中的指针或者偏移量。

  • 初始化:
  1. 给静态变量赋值,给成员变量分配内存,赋值

类加载器

JVM 中内置了三个重要的 ClassLoader,除了 BootstrapClassLoader 其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader

  1. BootstrapClassLoader(启动类加载器) :最顶层的加载类,由 C++实现,负责加载 %JAVA_HOME%/lib目录下的 jar 包和类或者被 -Xbootclasspath参数指定的路径中的所有类。
  2. ExtensionClassLoader(扩展类加载器) :主要负责加载 %JRE_HOME%/lib/ext 目录下的 jar 包和类,或被 java.ext.dirs 系统变量所指定的路径下的 jar 包。
  3. AppClassLoader(应用程序类加载器) :面向我们用户的加载器,负责加载当前应用 classpath 下的所有 jar 包和类。

双亲委派机制: 自底向上检查类是否被上层加载器加载,再从最顶向下尝试加载类

双亲委派机制的好处:

  1. 避免类的重复加载
  2. 保护Java核心API不被篡改

有关JVM的更多相关文章

  1. ruby - Scala 的扩展性是否优于其他 JVM 语言? - 2

    这是我目前知道的唯一询问方式。据了解,Scala使用Java虚拟机。我以为Jruby也是。Twitter将其中间件切换为Scala。他们可以做同样的事情并使用Jruby吗?他们是否可以从Jruby开始,而不是因为扩展问题导致他们首先从Ruby迁移到Scala?我不明白Jruby是什么吗?我假设因为Jruby可以使用Java,所以它可以扩展到Ruby不能的地方。在这种情况下,一切都归结为静态类型与动态类型吗? 最佳答案 Scala是“可扩展的”,因为语言可以通过库进行改进,使扩展看起来像是语言的一部分。这就是为什么actors看起来像

  2. xml - 如何使用 jvm-cucumber-parallel-plugin 重新运行失败的测试 - 2

    我正在使用jvmcucumber并行插件并想重新运行失败的测试用例。需要在.pom文件中进行哪些更改。com.github.temyerscucumber-jvm-parallel-plugin4.2.0generateRunnersgenerate-test-sourcesgenerateRunners${basedir}/target/runnercom.xxx.stepdefscom.xxx.cucumber.hookssrc/test/resources/feature${basedir}/target/cucumberreport/jsonjsontruejsontruepa

  3. windows - 通过 Windows 桌面快捷方式运行 Eclipse JVM 参数 - 2

    我想通过Windows上的桌面快捷方式运行Eclipse,并使用您可以在命令行上使用的-Duser.timezone参数。我的快捷方式目标如下所示:C:\Alan\SDK\3.7.1\eclipse.exe-vm"c:\ProgramFiles\Java\jdk1.6.0_22\bin\javaw.exe"-vmargs-Xmx512m-Xmx1024M-XX:PermSize=128M-XX:MaxPermSize=256M如您所见,我使用-X..参数增加了内存空间。无论出于何种原因,我都无法在-vmargs条目后键入-Duser.timezone=Europe/Dublin。不可能

  4. regex - 从命令输出中解析 WebSphere JVM 名称的 Windows 脚本 - 2

    我正在编写一个(批处理文件或VBScript)来很好地关闭Windows服务器上所有正在运行的WebSphereJVM,但需要一些文本处理方面的帮助。我希望脚本运行并解析“serverstatus”命令的输出以获取框中的ApplicationServers名称并将匹配项(带回车符)存储在用于脚本其余部分的变量。示例命令输出:C:\WebSphere\AppServer\bin>serverstatus-allADMU0116I:ToolinformationisbeingloggedinfileC:\WebSphere\AppServer\profiles\MySrv01\logs\s

  5. java - 在 JVM 运行时在 Windows 上创建符号链接(symbolic link) - 2

    有点奇怪的问题,但我在使用mklink创建符号链接(symboliclink)时遇到了问题在Windows7上。由于使用cmd.exe时存在260个字符的限制,我正在做一些奇怪的事情。通过使用Process在我的Java源代码中创建符号链接(symboliclink).由于我不能完全解释它,这里是代码:importjava.io.BufferedInputStream;importjava.io.BufferedReader;importjava.util.ArrayList;importjava.util.List;importjava.util.Map;importjava.uti

  6. java - JVM 在尝试获取信号量时卡住 - 2

    我有一个使用嵌入式Jetty(版本9.3.6.v20151106)和JDK8u65的应用程序。当我在Mac或Linux上使用这个应用程序时,我没有任何困难。但是,在Windows上,Jetty不会启动并且应用程序会永久挂起。我在进程上运行了一个jstack命令并隔离了阻止服务器启动的线程。java.lang.Thread.State:WAITING(parking)atsun.misc.Unsafe.park(NativeMethod)-parkingtowaitfor(ajava.util.concurrent.Semaphore$NonfairSync)atjava.util.co

  7. java - 不同windows操作系统的JVM - 2

    正如我们所知,JVM实现是特定于操作系统的(Windows/Linux/Solaris等)。我想更深入地研究一下,即我们是否针对不同的Windows操作系统版本有不同的JVM实现?例子:JVM-Implementation-For-Win-XP和JVM-Implementation-For-Win-8一样吗?? 最佳答案 IsJVM-Implementation-For-Win-XPsameasJVM-Implementation-For-Win-8??是也不是。它们大多使用相同的代码库,但各处存在一些差异。例如,WindowsXP

  8. java - Windows下JVM如何绘制按钮等控件? - 2

    虽然java程序是平台无关的,但JVM本身是平台相关的。我很想知道Java如何在屏幕上绘制应用程序GUI(按钮和文本)。在Windows下,控制objects例如按钮通常使用窗口(来自user32.dll)或矩形区域(来自gdi32.dll)创建,稍后使用提供的user32/gdi32文本绘制函数将文本绘制到相应的窗口/区域句柄。我尝试使用swing运行一个简单的双按钮Javagui应用程序,并从gdi32.dll和user32.dllHook大多数创建区域/窗口和文本绘制函数,但到目前为止,Java程序似乎只使用这些仅用于绘制主窗口框架的nativedll。Java.exe是否使用其

  9. java - 本地代码深处的 FileDialog.open() 偶尔导致 JVM 崩溃 - 2

    我目前面临的是在Windows2008服务器R2上的Citrix环境中运行的某些Eclipse应用程序中的异常访问冲突。通话开始于org.eclipse.swt.widgets.FileDialog.open(),调用org.eclipse.swt.internal.win32.OS.GetSaveFileNameW中的方法然后转到本地库。它失败了#EXCEPTION_ACCESS_VIOLATION(0xc0000005)atpc=0x68931bab,pid=9208,tid=7616与siginfo:ExceptionCode=0xc0000005,ExceptionInform

  10. java - 是否需要在每个操作系统上安装JVM才能运行java软件或java编译文件。? - 2

    Java是平台无关的,因为它的代码首先编译,然后JVM转换成操作系统可以理解的代码。所以我有疑问,我是否需要在每个操作系统上安装JVM? 最佳答案 操作系统无法理解没有任何翻译层的代码。JVM理解代码。您需要安装Java运行时(JRE),它可以在您希望运行Java代码的任何机器上运行JVM。这是因为java不是像C或C++这样的“native”代码,而是需要一些东西将指令转换为JVM所做的机器代码。 关于java-是否需要在每个操作系统上安装JVM才能运行java软件或java编译文件。

随机推荐