(1)内存模型以及分区,需要详细到每个区放什么。
堆:Java虚拟机管理内存中最大的一块,线程共享区域。所有对象实例和数组都在堆上分配内存空间。
栈:线程私有,每个线程都会创建一个虚拟机栈,生命周期与线程相同。每个方法被执行的时候就会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息。一个方法执行的过程对应着一个栈帧的入栈到出栈过程。
方法区:用于存储类信息,常量,静态变量等信息,是线程共享区域。
程序计数器:一块较小的内存空间,作用是当前执行字节码的行号指示器。
(2) 堆里面的分区:新生代(Eden,survival)老年代,各自的特点。
堆中存储对象实例,是垃圾回收的主要区域。为了方便垃圾回收,将堆区域分为新生代和老年代两个区域。
新生代:大量对象(98%)都是朝生夕死,因此在进行垃圾回收的时候采用复制算法进行垃圾回收,因为只需付出商量存货对象的复制成本就可以完成收集。但是由于新生代大量对象都是非存活状态,按照常规复制算法1:1划分内存会造成大量空间的浪费。因此新生代又可以划分为一块较大的Eden区域和两块较小的Survivor空间,每次使用Eden和其中一块Survivor区域。回收时,将存活的对象一次性拷贝到另一块Survivor空间上,再清理掉用过的Eden和Survivor空间。默认Eden区域:Survivor区域=8:1 也就是每次使用新生代容量的90%,只有10%被浪费。但是当Survivor区域不足 以存储回收后存活的对象时,需要老年代进行空间担保,这些对象直接通过分配担保机制进入老年代。
老年代:判断对象是否死亡,至少进行两次标记过程。如果对象在Eden出生并且经过一次gc后仍然存活,并且能够被Survivor容纳的话,将会被移动到Survivor区域,并将其年龄设置为1,如果它还能熬过下一次gc收集,年龄再+1.默认情况下当年龄到达15后,就会晋升到老年代中。老年代采用标记清除和标记整理算法进行垃圾收集。
(3)对象创建方法,对象的内存分配,对象的访问定位。
虚拟机遇到一个new指令时,首先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并检查这个符号引用代表的类是否已经被加载、解析和初始化过。如果没有,需要先执行相应的类加载过程。
对象创建,内存分配详解
对象访问定位符:
1.句柄访问方式:java堆中划分一部分空间作为句柄池,栈reference中存储对象的句柄地址,句柄中包含对象实例数据和各自对象具体地址。即对象实 例数据指针指向堆的实例池对象地址、对象类型数据指针指向方法区的对象类型数据。
优势:reference中存在稳定的句柄地址。对象被移动时只改变句柄中实例数据指针。
2.直接指针访问方式: reference中直接存储对象实例地址,对象实例数据中有一小块区域存储对象类型数据指针,同样指向方法区。
优势:节省了一次指针定位的开销,访问速度更快。
(4)GC的两种判定方法:引用计数与引用链
1.引用计数:给对象添加一个引用计数器,每当有一个地方引用它时,计数器加1。引用失效时,计数器减1 。当计数器为0时,对象就不可能再被使用。
残留问题:循环引用
2.引用链(可达性分析算法):通过Gc-Root的对象为起点,通过这个节点向下搜索,搜索所走过的路径为引用链。当一个对象到Gc-Root没有任何引用链连接时,证明对象不可用。
可作为Gc-Root的对象:
虚拟机栈中的引用对象。
本地方法栈中引用的对象。
方法区类静态属性引用的对象。
方法区中常量引用的对象。
(5)GC的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方。
1.标记清除算法:首先标记处所有需要回收的对象,在标记完成后统一进行回收。
缺点:标记的过程效率不高、标记清除之后产生大量不连续的内存碎片,当需要申请大块连续内存空间时,无法找到。
2.复制算法:将内存按容量费为大小相等的两块区域,每次只使用其中的一块,当一块内存用完了,就将还存活的对象复制到另一块内存上面,然后吧使用过的那块内存统一清理掉。
缺点:每次只能使用总内存容量的一半。在对象存活较多的情况下会进行大量复制操作,效率底下。
3.标记整理算法:和标记清除算法一样,先对死亡对象进行标记,然后将存活对象向一端移动,然后直接清理掉边界以外的内存。
4.分代收集算法:根据对象存活周期的不同,将内存划分为新生代和老年代,新生代使用复制算法,老年代使用标记清除或标记整理算法进行垃圾收集。
(6)GC收集器有哪些?CMS收集器与G1收集器的特点。
1.Serial:一个单线程的收集器,在进行垃圾收集时候,必须暂停其他所有的工作线程直到它收集结束。
特点:CPU利用率最高,停顿时间即用户等待时间比较长。
2.Parallel:采用多线程来通过扫描并压缩
特点:停顿时间短,回收效率高,对吞吐量要求高。
3.CMS收集器:采用“标记-清除”算法实现,使用多线程的算法去扫描堆,对发现未使用的对象进行回收。
4:G1:堆被划分成 许多个连续的区域(region)。采用G1算法进行回收,吸收了CMS收集器特点。
特点:支持很大的堆,高吞吐量、支持多CPU和垃圾回收线程、在主线程暂停的情况下,使用并行收集、在主线程运行的情况下,使用并发收集
(7)Minor GC与Full GC分别在什么时候发生?
Minor GC: 从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC。
特点:当 JVM 无法为一个新的对象分配空间时会触发 Minor GC,比如当 Eden 区满了。所以分配率越高,越频繁执行 Minor G。内存池被填满的时候,其中的内容全部会被复制,指针会从0开始跟踪空闲内存。Eden 和 Survivor 区进行了标记和复制操作,取代了经典的标记、扫描、压缩、清理操作。所以 Eden 和 Survivor 区不存在内存碎片。写指针总是停留在所使用内存池的顶部。
执行 Minor GC 操作时,不会影响到永久代。从永久代到年轻代的引用被当成 GC roots,从年轻代到永久代的引用在标记阶段被直接忽略掉。
质疑常规的认知,所有的 Minor GC 都会触发“全世界的暂停(stop-the-world)”,停止应用程序的线程。对于大部分应用程序,停顿导致的延迟都是可以忽略不计的。其中的真相就 是,大部分 Eden 区中的对象都能被认为是垃圾,永远也不会被复制到 Survivor 区或者老年代空间。如果正好相反,Eden 区大部分新生对象不符合 GC 条件,Minor GC 执行时暂停的时间将会长很多。
Major GC:清理永久代
Full GC:清理整个堆空间—包括年轻代和永久代
Major GC / Full GC:老年代 GC(Major GC / Full GC):指发生在老年代的 GC,出现了 Major GC,经常会伴随至少一次的 Minor GC(但非绝对的,在 ParallelScavenge 收集器的收集策略里就有直接进行 Major GC 的策略选择过程) 。MajorGC 的速度一般会比 Minor GC 慢 10倍以上。
(8) 双亲委派模型:Bootstrap ClassLoader、Extension ClassLoader、ApplicationClassLoader。
JDK 默认提供了如下几种ClassLoader
1. Bootstrp loader
Bootstrp加载器是用C++语言写的,它是在Java虚拟机启动后初始化的,它主要负责加载%JAVA_HOME%/jre/lib,-Xbootclasspath参数指定的路径以及%JAVA_HOME%/jre/classes中的类。
1. ExtClassLoader
Bootstrp loader加载ExtClassLoader,并且将ExtClassLoader的父加载器设置为Bootstrploader.ExtClassLoader是用Java写的,具体来说就是 sun.misc.LauncherExtClassLoader,ExtClassLoader主要加载2.AppClassLoaderBootstrploader加载完ExtClassLoader后,就会加载AppClassLoader,并且将AppClassLoader的父加载器指定为ExtClassLoader。AppClassLoader也是用Java写成的,它的实现类是sun.misc.Launcher AppClassLoader,另外我们知道ClassLoader中有个getSystemClassLoader方法,此方法返回的正是AppclassLoader.AppClassLoader主要负责加载classpath所指定的位置的类或者是jar文档,它也是Java程序默认的类加载器。
综上所述,它们之间的关系可以通过下图形象的描述:
双亲委托模型
Java中ClassLoader的加载采用了双亲委托机制,采用双亲委托机制加载类的时候采用如下的几个步骤:
1. 当前ClassLoader首先从自己已经加载的类中查询是否此类已经加载,如果已经加载则直接返回原来已经加载的类。
每个类加载器都有自己的加载缓存,当一个类被加载了以后就会放入缓存,等下次加载的时候就可以直接返回了。
2. 当前classLoader的缓存中没有找到被加载的类的时候,委托父类加载器去加载,父类加载器采用同样的策略,首先查看自己的缓存,然后委托父类的父类去加载,一直到bootstrp ClassLoader.
3. 当所有的父类加载器都没有加载的时候,再由当前的类加载器加载,并将其放入它自己的缓存中,以便下次有加载请求的时候直接返回。
说到这里大家可能会想,Java为什么要采用这样的委托机制?理解这个问题,我们引入另外一个关于Classloader的概念“命名空间”, 它是指要确定某一个类,需要类的全限定名以及加载此类的ClassLoader来共同确定。也就是说即使两个类的全限定名是相同的,但是因为不同的ClassLoader加载了此类,
那么在JVM中它是不同的类。明白了命名空间以后,我们再来看看委托模型。采用了委托模型以后加大了不同的 ClassLoader的交互能力,比如上面说的,我们JDK本生提供的类库,比如hashmap,linkedlist等等,这些类由bootstrp 类加载器加载了以后,无论你程序中有多少个类加载器,那么这些类其实都是可以共享的,这样就避免了不同的类加载器加载了同样名字的不同类以后造成混乱。
如何自定义ClassLoader
Java除了上面所说的默认提供的classloader以外,它还容许应用程序可以自定义classloader,那么要想自定义classloader我们需要通过继承java.lang.ClassLoader来实现,接下来我们就来看看再自定义Classloader的时候,我们需要注意的几个重要的方法:
1.loadClass 方法
loadClass method declare public Class<?> loadClass(String name) throws ClassNotFoundException
上面是loadClass方法的原型声明,上面所说的双亲委托机制的实现其实就实在此方法中实现的。下面我们就来看看此方法的代码来看看它到底如何实现双亲委托的。
loadClass method implement public Class<?> loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); }
从上面可以看出loadClass方法调用了loadcClass(name,false)方法,那么接下来我们再来看看另外一个loadClass方法的实现。
Class loadClass(String name, boolean resolve) protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { // First, check if the class has already been loaded Class c = findLoadedClass(name); //检查class是否已经被加载过了 if (c == null) { try { if (parent != null) { c = parent.loadClass(name, false); //如果没有被加载,且指定了父类加载器,则委托父加载器加载。 } else { c = findBootstrapClass0(name);//如果没有父类加载器,则委托bootstrap加载器加载 } } catch (ClassNotFoundException e) { // If still not found, then invoke findClass in order // to find the class. c = findClass(name);//如果父类加载没有加载到,则通过自己的findClass来加载。 } } if (resolve) { resolveClass(c); } return c; }
相关推荐
了解并掌握这些JVM基础知识对于编写高性能、低内存消耗的Java程序至关重要。开发者可以通过理解JVM的工作原理,优化代码,避免内存溢出,提升应用的运行效率。此外,对JVM的深入研究也能帮助我们更好地理解Java平台...
综上所述,文件中提供的内容是对JVM基础知识的一个概览,涵盖了Class文件格式、字节码、类加载机制、运行时数据区、垃圾回收策略、以及JVM在其他语言中的应用等多个方面。高级篇和优化篇预计会对JVM的高级特性和调优...
1、java文件编译过程 2、运行时数据区详细介绍 3、类加载原理
标题《JVM系列之性能调优参考手册(实践篇)》涉及的知识点主要集中在Java虚拟机(JVM)性能调优的实践操作。JVM作为Java程序运行的基础环境,对程序性能有着决定性影响。本手册的目的是指导开发者如何对JVM进行性能...
总结,了解JVM的这些基础知识是成为一名合格的Java开发者的必经之路。深入学习JVM,不仅可以提升编程技能,还能帮助解决性能问题,使代码运行更加高效。通过实践和不断探索,我们可以更好地理解和利用这个强大的平台...
《Java语言程序设计》是Y.Daniel Liang与梁勇合作编写的一本经典教材,分为基础篇和进阶篇,涵盖了Java编程的各个方面。这个压缩包包含的是书中的所有源代码,供读者学习和实践使用。以下是根据这些信息提炼出的一些...
Java程序语言设计是Java开发者学习过程中的一本经典教材,梁勇教授的第十版结合了基础篇与进阶篇,深入浅出地讲解了Java编程的核心概念和技术。此压缩包包含了该书的课后习题答案,对于正在学习或已经学过这本书的...
《Java语言程序设计(基础篇+进阶篇)第六版》是Java学习的重要参考资料,尤其对于初学者和希望深入理解Java编程概念的人来说,这是一本不可多得的教材。本书分为基础篇和进阶篇,涵盖了Java编程的各个方面,旨在帮助...
学习"JAVA程序员必读基础篇"的内容,将帮助初学者建立起坚实的Java编程基础,为进一步深入学习Java高级特性,如Spring框架、JDBC数据库访问、多线程编程等打下坚实的基础。通过实践和不断练习,你将能够熟练掌握这个...
基础篇主要涵盖了Java编程语言的基本概念、语法和核心特性,是学习Java编程的入门指南。这篇教程旨在帮助初学者理解并掌握Java语言的基础知识,为更深入的Java开发打下坚实的基础。 首先,Java语言简介是学习的起点...
JVM是Java程序运行的基础,它负责解析、编译、执行Java代码,并管理内存。本篇文章将围绕JVM的内存模型、垃圾收集机制以及G1 GC的特性进行详细的阐述。 首先,JVM的内存模型包括堆内存和非堆内存两大部分。堆内存...
### JVM调优详解 #### 一、JVM调优概述 在现代软件开发中,Java虚拟机(JVM)作为Java应用程序的运行环境,...通过本篇文章的学习,希望读者能够掌握JVM调优的基本原理和技术手段,为日常开发工作提供有力的支持。
Java语言程序设计基础篇 Java语言作为一门广泛应用于企业级应用、移动开发、云计算和大数据处理等领域的编程语言,其基础知识对于任何想要进入这个领域的学习者来说都是至关重要的。本资料"Java语言程序设计基础篇...
### JVM基础知识 1. **什么是JVM**:Java虚拟机(Java Virtual Machine,简称JVM)是一种用于执行Java字节码的虚拟机。它为Java程序提供了运行时环境,可以独立于操作系统和硬件平台运行Java应用程序。 2. **JVM的...
《Java语言程序设计 基础篇 第10版 梁勇 答案》是一本针对初学者和进阶者的重要参考资料,由知名Java教育专家梁勇编写。本书全面覆盖了Java语言的基础概念、语法和编程技巧,旨在帮助读者深入理解并掌握Java编程的...
这个"Java语言程序设计基础篇源代码"压缩包包含了学习Java编程的基础教程和示例代码,对于初学者而言是一份非常宝贵的资源。 Java的核心特性包括它的跨平台性(Write Once, Run Anywhere),这是通过Java虚拟机...
《Java语言程序设计第八版》基础篇和进阶篇的示例代码集合是一个全面的资源库,对于学习和深入理解Java编程语言至关重要。这个压缩包包含的不仅仅是代码,还涵盖了各种辅助资源,如音频、图片和必要的jar包,旨在...
本篇JVM学习笔记主要涵盖了以下几个核心知识点: 1. **运行时数据区**: - **程序计数器**:记录当前线程执行的字节码的行号,用于线程恢复执行时跳转到正确位置。 - **Java虚拟机栈**:每个方法执行时创建的栈帧...
### 从 0 开始带你成为JVM实战高手...以上内容基于标题、描述及部分给定信息进行了详细的知识点梳理,涵盖了JVM的基础概念、内部机制以及实际操作技巧等多个方面,希望能够帮助读者系统地学习并掌握JVM的相关知识。