一.JVM相关

1.String str=“haha”,这个字符串对象在栈内存中明明有一个引用(str[ox00014]),为什么说这个字符串是匿名对象呢?**

所谓的字符串是匿名对象,实际上是因为只要使用了“’’”声明,那么就表示将在堆内存空间里面开辟一个新的字符串对象(String对象),这个对象是可以直接使用的,例如:““haha”.length()”。“haha”这个时候还没有被引用,称为称为匿名对象,如果此时的“String str=“haha””,已经明确的为str对象进行实例化,所以“hello”对应的堆内存的地址已经有了明确的栈内存指向,就不是匿名对象了。

2.JVM内存优化

(1)JVM优化的第一个问题,取消掉伸缩区,让total=max;
—— CMS问题,频繁的CMS会导致性能下降;
——伊甸园区、存活区、老年代的关系要说明白,JDK1.8之后取消了永久代,而使用元空间代替。
(2)如果你的内存过大,要使用GI收集器来进行收集;
(3)在Tomcat里面由于其使用基于JVM,所以需要设置一个“JAVA OPTS”指令,可以将全部的内存供Tomcat使用(默认的最大可用内存为全部内存的四分之一,默认的total内存为全部内存的64分之1)。

3.JVM内存组成

JVM内存组成里面最为关键的几个内存:
(1)栈内存:只是保存有堆内存的引用地址,而且从一个简单的角度来讲,栈内存可以保存基本类型;
(2)堆内存:Java没有采用句柄的模式进行引用,所以它的引用性能是最高的,但是从另外一个角度来讲,堆内存里面实际上又分为若干个子内存空间:伊甸园区、存活区、老年代(FullGC、MajorGC);
①原则:少产生无用的大量内存空间,因为会引发频繁的GC,而频繁的GC会带来CMS问题,那么会导致程序中断执行,所以这个处理的原则之中对于程序员的要求;
②让你初始化的空间大小等于整个堆内存的分配大小,避免伸缩区,这样可以进行性能的提升;
(3)方法区(JDK1.8以前可以称为永久代,在JDK1.8之后称为元空间);
(4)全局数据区也可以认为其规划在堆内存里面,因为会发现全局数据区中保存的内容有可能是对象,有可能是基本类型,只不过它采用了一种特殊的处理形式而已。
在面试中还有可能问到的是堆内存的组成以及GC的处理流程。

4.java内存模型

1.伊甸园区:新生的对象都保存在此处,但这些新生的对象不一定会一直存活;
此处也属于内存空间,既然是内存空间一定会被占满,如果占满了,就会执行GC操作;
2.旧生代区:如果某些对象其要一直使用,那么就将进入到旧生代区,这属于二级回收保险;
如果要先执行GC,那么肯定先清理伊甸园区,随后如果发现空间不足,继续清理旧生代区;
3.永久区:永久区中的数据不会清除,即使程序出现了“OutOfMemoryError”也不会清除。

调整内存大小:-Xms2048M-Xmx2048M-Xmn1024M
(1)“-Xms”:初始分配的内存大小,默认在物理内存的64分之1,但是小于1G;
(2)“-Xmx”:最大分配内存,默认大小为物理内存的4分之1,但是小于1G;
(3)“-Xmn”:设置年轻代(伊甸园区)的堆内存大小;

5.为什么不把基本数据类型放在堆中?

首先是栈、堆的特点不同。(堆比栈要大,但是栈比堆的运算速度要快。)
将复杂数据类型放在堆中的目的是为了不影响栈的效率,而是通过引用的方式去堆中查找。〔八大基本类型的大小创建时候已经确立大小。三大引用类型创建时候无法确定大小)
简单数据类型比较稳定,并且它只占据很小的内存,将它放在空间小、运算速度快的栈中,能够提高效率。

6.Class.forName( “Java.lang.String”)和Class.getclassLoader().loadclass( “Java.lang.String”)有什么区别

Class.forName( “Java.lang.String”)会引发类的初始化
ClassLoader.getSystemClassLoader().loadClass(“test.jvm.ClassTest”);不会进行初始化,只会执行类加载过程的第一步loading(将字节码转换成.class文件)

7.什么时候会触发类的加载

Java虚拟机规定,一个类或接口在初次使用前,必须要进行初始化。这里指的“使用”,是指主动使用。
主动使用只有下列几种情况:(即:如果出现如下的情况,则会对类进行初始化操作。而初始化操作之前的加载、验证、准备已经完成。>
1.当创建一个类的实例时,比如使用new关键字,或者通过反射、克隆、反序列化。
2.当调用类的静态方法时,即当使用了字节码invokestatic指令。
3.当使用类、接口的静态字段时(final修饰特殊考虑),比如,使用getstatic或者putstatic指令。
4.当使用java.lang.reflect包中的方法反射类的方法时。比如:Class.forName( “com.java.Test” )
5.当初始化子类时,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化
6.如果一个接口定义了default方法,那么直接实现或者间接实现该接口的类的初始化,该接口要在其之前被初始化。
7.当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚扎机会先初始化这个主类。

8.既然Tomcat不遵循双亲委派机制,那么如果我自己定义一个恶意的HashMap,会不会有风险呢?

tomcat不遵循双亲委派机制,只是自定义的classLoader顺序不同,但顶层还是相同的,还是要去顶层请求classloader。

9. Tomcat是个web容器,那么它要解决什么问题?

  1. 一个web容器可能需要部署两个应用程序,不同的应用程序可能会依赖同一个第三方类库的不同版本,不能要求同一个类库在同一个服务器只有一份,因此要保证每个应用程序的类库都是独立的,保证相互隔离。
  2. 部署在同一个web容器中相同的类库相同的版本可以共享。否则,如果服务器有10个应用程序,那么要有10份相同的类库加载进虚拟机。
  3. web容器也有自己依赖的类库,不能于应用程序的类库混淆。基于安全考虑,应该让容器的类库和程序的类库隔离开来。
  4. web容器要支持jsp的修改,我们知道,jsp文件最终也是要编译成class文件才能在虚拟机中运行,但程序运行后修改jsp已经是司空见惯的事情,否则要你何用?所以,web容器需要支持jsp修改后不用重启。

10.为什么java文件放在Eclipse/IDEA中的src文件夹下会优先jar包中的class?

  • tomcat类加载机制的理解,就不难明白。因为Eclipse/IDEA中的src文件夹中的文件java以及webContent中的SP都会在tomcat启动时,被编译成class文件放在 WEB-INF/class 中
    而Eclipse/IDEA外部引用的jar包,则相当于放在WEB-INF/lib 中。

11.栈和堆的区别

  1. 栈不存在GC 堆存在
  2. 栈的效率要高于堆
  3. 栈先进后出,内存非常小
  4. 栈管运行,堆管存储

12.初始堆大小和最大堆大小一样,这样有什么好处?

  • 通常会将 -Xms和 -Xmx两个参数配置相同的值,其目的是为了能够在java垃圾回收机制清理完堆区后不需要重新分隔计算堆区的大小,从而提高性能。

13.堆空间一般设置多大

  • heap默认最大值计算方式:如果物理内存少于192M,那么heap最大值为物理内存的一半。如果物理内存大于等于1G,那么heap的最大值为物理内存的1/4。
    heap默认最小值计算方式:最少不得少于8M,如果物理内存大于等于16,那么默认值为物理内存的1/64,即1024/64=16M。最小堆内存在jvm启动的时候就会被初始化。

14.Minor GC、MaijorGC 和FullGC解释说明

针对HotSpot VM的实现,它里面的GC按照回收区域又分为两大种类型:

  • 部分收集(Partial Gc)

    • 新生代收集(Minor GC / Young GC):只是新生代(Eden\s0,s1)的垃圾收集
    • 老年代收集(Major Gc / old Gc):只是老年代的垃圾收集。(只有CMS GC会有 单独收集老年代的行为
    • 混合收集(Mixed Gc):收集整个新生代以及部分老年代的垃圾收集。目前,只有G1 GC会有这种行为
  • 整堆收集(Full GC):收集整个java堆和方法区的垃圾收集。

15、Full GC的触发机制

(1)调用system.gc()时,系统建议执行Full Gc,但是不必然执行(2)老年代空间不足
(3)方法区空间不足
(4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存
(5)由Eden区、survivor space0 (From Space)区向survivor space1(To Space)区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小

16.为什么永久代要换为元空间

方法区中的类很难卸载,不好移除并且难以回收,所以换成元空间,使用本地内存

17、堆是分配对象的唯一选择嘛

是—-》不是—》是
在Java虚拟机中,对象是在Java堆中分配内存的,这是一个普遍的常识。
但是,有一种特殊情况,那就是如果经过逃逸分析(Escape Analysis)后发现,一个对象并没有逃逸出方法的话,那么就可能被优化成栈上分配。这样就无需在堆上分配内存,也无须进行垃圾回收了。
但是放的对象不是真正的对象,而是会进行一个标量替换,也可以说不是

18.有一个50万Pv的资料类网站(从磁盘提取文档到内存)原服务器是32位的,1.5G的堆,用户反馈网站比较缓慢。因此公司决定升级,新的服务器为64位,16G的堆内存,结果用户反馈卡顿十分严重,反而比以前效率更低了!

  1. 为什么原网站慢?
    频繁的GC,STw时间比较长,响应时间慢!
  2. 为什么会更卡顿?
    内存空间越大,FGC时间更长,延迟时间更长
  3. 怎么解决这个问题?
  • 垃圾回收器: parallel Gc ; ParNew + CMS ; G1
  • 配置GC参数:-XX:MaxGCPauseMillis 、-XX:ConcGCThreads
  • 根据log日志、dump文件分析,优化内存空间的比例
    jstat jinfo jstack jmapl

19、CPU占用100%怎么排查?

1、ps aux / grep java 查看到当前java进程使用cpu、内存、磁盘的情况获取使用量异常的进程
2、top -Hp 进程pid检查当前使用异常线程的pid
3、把线程pid变为16进制如31695-》 7bcf 然后得到Ox7bcf
4、查看信息(2种方式)

  • 1.jstack+进程的pid l grep -A20 Ox7bcf得到相关进程的代码
  • 2.将信息打印到文件中 jstack pid > 文件名
  1. public static void main (string [] args) {
  2. alloc ( );
  3. }
  4. private static void alloc(){
  5. Point point = new Point 1,2);
  6. system.out.println ( "point.x="+point.x+"; point.y="+point.y);
  7. class Point {
  8. private int x;
  9. private int y;
  10. }
  11. 以上代码,经过标量替换后,就会变成:
  12. private static void alloc(){
  13. int x = l;
  14. int y = 2;
  15. system.out.println ( "point.x="X+" ; point.y="+y);
  1. 问题一:栈溢出的情况?栈溢出:StackOverflowError;
  2. 举个简单的例子:在main方法中调用main方法,就会不断压栈执行,直到栈溢出;栈的大小可以是固定大小的,也可以是动态变化(动态扩展)的。
  3. 如果是固定的,可以通过-Xss设置栈的大小;
  4. 如果是动态变化的,当栈大小到达了整个内存空间不足了,就是抛出outOfMemory异常(java.lang.outOfMemoryError)
  5. 问题二:调整栈大小,就能保证不出现溢出吗?
  6. 不能。因为调整栈大小,只会减少出现溢出的可能,栈大小不是可以无限扩大的,所以不能保证不出现溢出
  7. 问题三:分配的栈内存越大越好吗?
  8. 不是,因为增加栈大小,会造成每个线程的栈都变的很大,使得一定的栈空间下,能创建的线程数量会变小
  9. 问题四:垃圾回收是否会涉及到虚拟机栈?
  10. 不会;垃圾回收只会涉及到方法区和堆中,方法区和堆也会存在溢出的可能;程序计数器,只记录运行下一行的地址,不存在溢出和垃圾回收;
  11. 虚拟机栈和本地方法栈,都是只涉及压栈和出栈,可能存在栈溢出,不存在垃圾回收。
  12. 问题五:方法中定义的局部变量是否线程安全?
  13. 如果被其他方法中的局部变量中引用也是不安全的
  1. 1. private修饰的方法可以通过反射访问,那么private的意义是什么2.Java类初始化顺序
  2. 3.对方法区和永久区的理解以及它们之间的关系4.一个java文件有3个类,编译后有几个class文件
  3. 5.局部变量使用前需要显式地赋值,否则编译通过不了,为什么这么设计6.ReadWriteLock读写之间互斥吗
  4. 7.Semaphore拿到执行权的线程之间是否互斥8.写一个你认为最好的单例模式
  5. 9.B树和B+树是解决什么样的问题的,怎样演化过来,之间区别10.写一个生产者消费者模式
  6. 11.写一个死锁
  7. 12.cpu 100%怎样定位
  8. 13.String a = "ab"; String b = "a" + b"; a == b是否相等,为什么14.int a = 1;是原子性操作吗
  9. 15.可以用for循环直接删除ArrayList的特定元素吗?可能会出现什么问题?怎样解决16.新的任务提交到线程池,线程池是怎样处理
  10. 17.AQS和CAS原理
  11. 18.synchronized底层实现原理19.volatile作用,指令重排相关20.AOP和IOC原理
  12. 21.Spring怎样解决循环依赖的问题22.dispatchServlet怎样分发任务的
  13. 23.mysql给离散度低的字段建立索引会出现什么问题,具体说下原因
  14. ~~~
  15. ~~~
  16. 如果想统一项目的线程池,包括三方引入包的线程池,怎么处理。(最后解答可通过字节码修改实现)
  17. 如果想监控某一线程的耗时超过300毫秒的任务需要怎么操作。(可反射获取Handler抓取每个Message的执行耗时)
  18. 如果项目出现未捕获的异常,怎么预操作可以防止Crash。
  19. 如果设计一个App的启动框架,需要考虑什么问题,怎么处理同步异步的加载任务调度。
  20. glide 加载原理,怎么感知加载和暂停。
  21. okhttp加载原理,怎么控制同步和异步任务。
  22. 说一个项目难点,具体怎么解决的。
  23. 都用过什么设计模式。
  24. mvp mvvm都在什么场景下使用。
  25. 一个int数组怎么判断是搜索二叉树的后续遍历。
  26. 如果给你足够的人,足够的钱,足够的资源,让你去学油画,你应该怎么做?
  27. ~~~