江西通威公路建设集团有限公司网站,淘宝客网站怎么做推广计划,wordpress 点赞分享,衡水seo外包久违的重新写了一篇面试汇总的#xff0c;关于JVM的一篇#xff0c;一共三篇#xff0c;今天写了第一篇#xff0c;继续重新学习#xff0c;重新卷起来#xff0c;come on baby 1.什么情况下会触发类的初始化#xff1f; #xff08;1#xff09;首先是类未被初始化时… 久违的重新写了一篇面试汇总的关于JVM的一篇一共三篇今天写了第一篇继续重新学习重新卷起来come on baby 1.什么情况下会触发类的初始化 1首先是类未被初始化时创建类的实例(new 的方式)访问某个类或接口的静态变量或者对该静态变量赋值调用类的静态方法。 2对类进行反射调用的时候如果类没有进行过初始化则需要先触发其初始化。 3如果在初始化某一个类时候其父类没有被初始化时候则会触发父类的初始化。 4当咱们打的jar包在执行完java -jar命令后用户需要指定一个要执行的主类包含 main() 方法的那个类例如SpringBoot的那个启动类的main方法非SpringBoot的咱们自己手动打包的一般在MANIFEST.MF文件中指定虚拟机会先初始化这个主类。 5JDK 1.7新增了一种反射方式java.lang.invoke.MethodHandle通过实MethodHandle同样是访问静态变量对该静态变量赋值调用类的静态方法前提仍然是该类未被初始化。 2.谈谈你对解析与分派的认识。 1解析调用是将那些在编译期就完全确定在类加载的解析阶段就将涉及的符号引用全部转变为可以确定的直接引用不会延迟到运行期再去完成。 2分派又分为静态分派和动态分派 3静态分派同样是将编译期确定的调用重载Oveload就是这种类型在编译期通过参数的静态类型注意不是实际类型作为判断依据找到具体的调用的方法。 public class TestOverLoad {public static void main(String[] args) {//静态类型都是Parent实际类型分别是Sun和DaughterParent sun new Sun();Parent daughter new Daughter();TestOverLoad test new TestOverLoad();//输出结果按照静态类型执行test.testMethod(sun);test.testMethod(daughter);}static abstract class Parent { }static class Sun extends Parent { }static class Daughter extends Parent { }public void testMethod(Parent parent) {System.out.println(hello, Parent);}public void testMethod(Sun sun) {System.out.println(hello, Sun);}public void testMethod(Daughter daughter) {System.out.println(hello, Daughter);}
}//输出
hello, Parent
hello, Parent4动态分派运行期根据实际类型确定方法执行版本的分派过程称为动态分派。重写Override在运行时期通过判断实体的真实类型判断具体执行哪一个方法。 public class TestOverride {public static void main(String[] args) {//静态类型都是Parent实际类型分别是Sun和DaughterParent sun new Sun();Parent daughter new Daughter();//这时候输出结果按照实际类型找到方法sun.testMethod();daughter.testMethod();}static abstract class Parent {public void testMethod() {System.out.println(hello, Parent);}}static class Sun extends Parent {Overridepublic void testMethod() {System.out.println(hello, Sun);}}static class Daughter extends Parent {Overridepublic void testMethod() {System.out.println(hello, Daughter);}}
}
//输出
hello, Sun
hello, Daughter3.Java类加载器包括⼏种它们之间的⽗⼦关系是怎么样的双亲委派机制是什么意思有什么好处 1启动类加载器Bootstrap ClassLoader由C语言编写的。负责把JAVA_HOME\lib目录中的类库加载到虚拟机内存中。 2扩展类加载器Extension ClassLoader这个加载器由sun.misc.LauncherApp-ClassLoader实现。由于这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值所以一般也称它为系统类加载器。它负责加载用户类路径ClassPath上所指定的类库开发者可以直接使用这个类加载器如果应用程序中没有自定义过自己的类加载器一般情况下这个就是程序中默认的类加载器。 4自定义类加载器。下面是自定义类加载器的方式这个有几点注意TestDemo编译出来class把class复制到idea或者eclipse生成target目录之外因为需要删除掉TestDemo.java这样target下的class可能也自动没有了另外如果不删除TestDemo.java会导致一直输出默认的应用程序加载器因为你运行环境里有双亲委派的应用程序加载器能找TestDemo所以默认用父类的了所以必须删除掉。 package test;public class TestDemo {private String name;public TestDemo(){}public TestDemo(String name){this.name name;}public String getName(){return name;}public void setName(String name){this.name name;}public String toString(){return Demo name is name;}
}
package test;import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;public class TestMyClassLoader extends ClassLoader
{public TestMyClassLoader(){}public TestMyClassLoader(ClassLoader parent){super(parent);}protected Class? findClass(String name) throws ClassNotFoundException{File file getClassFile(name);try{byte[] bytes getClassBytes(file);Class? c this.defineClass(name, bytes, 0, bytes.length);return c;}catch (Exception e){e.printStackTrace();}return super.findClass(name);}private File getClassFile(String name){//重点是这个路径在本地编译好TestDemo后把class放在一个其他路径下//不要默认用idea或者eclipse的target路径//注意运行这个类之前把代码的TestDemo.java删除掉或者注释掉//否则怎么运行都是默认的加载器AppClassLoaderFile file new File(/Users/buxuesong/TestDemo.class);return file;}private byte[] getClassBytes(File file) throws Exception{// 这里要读入.class的字节因此要使用字节流FileInputStream fis new FileInputStream(file);FileChannel fc fis.getChannel();ByteArrayOutputStream baos new ByteArrayOutputStream();WritableByteChannel wbc Channels.newChannel(baos);ByteBuffer by ByteBuffer.allocate(1024);while (true){int i fc.read(by);if (i 0 || i -1)break;by.flip();wbc.write(by);by.clear();}fis.close();return baos.toByteArray();}public static void main(String[] args) throws Exception{TestMyClassLoader mcl new TestMyClassLoader();Class? c1 Class.forName(test.TestDemo, true, mcl);Object obj c1.newInstance();System.out.println(obj);System.out.println(obj.getClass().getClassLoader());}
}
//输出
Demo name is null
test.TestMyClassLoader5cad8086
//如果没删除TestDemo.java输出
Demo name is null
sun.misc.Launcher$AppClassLoader18b4aac25扩展类加载器的父类是启动类加载器应用程序类加载器的父类是扩展类加载器自定义类加载器的父类是应用程序类加载器。 6双亲委派机制:除了启动类加载器其余加载器都应该有自己的父类加载器当一个类加载器需要加载某个类时默认把这个累交给自己的父类去加载只有当父类无法加载这个类时候它的搜索范围中没有找到所需的类自己才去加载按照这个规则所有的累加载最终都会到启动类加载器过一遍。 7双亲委派实际上保障了Java程序的稳定运作因为随着这种父类关系自带了一种层级关系按照层级关系来分别加载如果不按照顺序各个加载器自行加载用户如果自己写了一个java. lang.Object的类系统会出现多个Object类导致整个java体系无法运转。 4.如何⾃定义⼀个类加载器你使⽤过哪些或者你在什么场景下需要⼀个⾃定义的类加载器吗 1这问题问了我上面的我在写一遍自定义类加载器有几点注意TestDemo编译出来class把class复制到idea或者eclipse生成target目录之外因为需要删除掉TestDemo.java这样target下的class可能也自动没有了另外如果不删除TestDemo.java会导致一直输出默认的应用程序加载器因为你运行环境里有双亲委派的应用程序加载器能找TestDemo所以默认用父类的了所以必须删除掉。 package test;public class TestDemo {private String name;public TestDemo(){}public TestDemo(String name){this.name name;}public String getName(){return name;}public void setName(String name){this.name name;}public String toString(){return Demo name is name;}
}
package test;import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;public class TestMyClassLoader extends ClassLoader
{public TestMyClassLoader(){}public TestMyClassLoader(ClassLoader parent){super(parent);}protected Class? findClass(String name) throws ClassNotFoundException{File file getClassFile(name);try{byte[] bytes getClassBytes(file);Class? c this.defineClass(name, bytes, 0, bytes.length);return c;}catch (Exception e){e.printStackTrace();}return super.findClass(name);}private File getClassFile(String name){//重点是这个路径在本地编译好TestDemo后把class放在一个其他路径下//不要默认用idea或者eclipse的target路径//注意运行这个类之前把代码的TestDemo.java删除掉或者注释掉//否则怎么运行都是默认的加载器AppClassLoaderFile file new File(/Users/buxuesong/TestDemo.class);return file;}private byte[] getClassBytes(File file) throws Exception{// 这里要读入.class的字节因此要使用字节流FileInputStream fis new FileInputStream(file);FileChannel fc fis.getChannel();ByteArrayOutputStream baos new ByteArrayOutputStream();WritableByteChannel wbc Channels.newChannel(baos);ByteBuffer by ByteBuffer.allocate(1024);while (true){int i fc.read(by);if (i 0 || i -1)break;by.flip();wbc.write(by);by.clear();}fis.close();return baos.toByteArray();}public static void main(String[] args) throws Exception{TestMyClassLoader mcl new TestMyClassLoader();Class? c1 Class.forName(test.TestDemo, true, mcl);Object obj c1.newInstance();System.out.println(obj);System.out.println(obj.getClass().getClassLoader());}
}
//输出
Demo name is null
test.TestMyClassLoader5cad8086
//如果没删除TestDemo.java输出
Demo name is null
sun.misc.Launcher$AppClassLoader18b4aac22我们之前写的获取数据库连接通过class.forname去加载数据库驱动。以及热加载这种方式咱们修改了java文件但是tomcat没有手动重启这个时候有一个能够监控到java有变化重新编译了的情况通过线程出发tomcat重启就达到了热加载的机制。还有就是apk加密的方式打包时候源码-》class-》加密-》打成jar包-》安装-》运行-》classLoader解密-》classLoader加载-》用户使用app这样只有实现解密方法的classloader才能正常加载其他的classLoader无法运行。 5.堆内存设置的参数是什么 1-Xms初始堆内存大小 2-Xmx最大堆内存大小生产环境中JVM的Xms和Xmx建议设置成一样的能够避免GC时还要调整堆大小。 3-XX:NewSizen设置年轻代大小-XX:NewRation设置年轻代和年老代的比值。如:-XX:NewRatio3表示年轻代与年老代比值为13年轻代占整个年轻代年老代和的1/4默认新生代和老年代的比例1:2 4-XX:SurvivorRation设置年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个默认是8表示Eden:S0:S18:1:1如-XX:SurvivorRatio3表示EdenSurvivor32一个Survivor区占整个年轻代的1/5。 5-XX:HeapDumpOnOutOfMemoryError-XX:HeapDumpPath这两个是设置但程序OOM后输出Dump文件以供分析原因的但是对于目前的K8s的情况这俩没什么用OOM之后K8s发现服务没响应直接kill了然后重启一个新的OOM根本就来不及生成因为生成文件耗时较多K8s杀的很快。 6-Xss128k 设置每个线程的堆栈大小。 7-XX:PrintGCDetails输出GC日志。 感谢各位的阅读帮忙点赞感谢各位。 最后编辑于2025-06-22 10:05:52 © 著作权归作者所有,转载或内容合作请联系作者 平台声明文章内容如有图片或视频亦包括在内由作者上传并发布文章内容仅代表作者本人观点简书系信息发布平台仅提供信息存储服务 喜欢的朋友记得点赞、收藏、关注哦