美文网首页
JAVA面试汇总(四)JVM(二)

JAVA面试汇总(四)JVM(二)

作者: 汤太咸啊 | 来源:发表于2022-01-19 23:29 被阅读0次
久违的面试汇总JVM的第二篇,还有第三篇,继续学习,卷起来,come on baby

6.在JVM中,如何判断一个对象是否死亡?

(1)通过引用计数算法,引用计数器,每当一个地方引用这个对象的时候,计数器就加1,当引用失效,计数器就减1;任何时刻计数器为0的对象就是不可能再被使用了。实现简单,效率高,但是它很难解决对象的循环引用问题。
(2)可达性分析算法,这个算法的基本思路是通过一系列称为“GC Roots”(一组必须活跃的引用)作为起始点,从这些节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何引用链时候,那么证明此对象是不可用的。
(3)但是上面两种算法都不能直接判定对象已经死亡,只有gc时,针对两种算法都已经失效的情况下,对两个对象回收后才真正算是死亡。

7.Perm Space中保存什么数据?会引起OutOfMemory吗?

(1)全称是Permanent Generation space,是指内存的永久保存区域。该块内存主要是被JVM用来存储类的元信息、类变量以及内部字符串(interned string)等内容。Perm Space使用的JVM内存。在JDK1.8被元空(Metaspace)替代。永久代是hotspot VM的实现特有的。
(2)Metaspace没有存储字符串常量池,而在jdk7的时候已经被移动到了堆中,MetaSpace其他存储的东西,包括类文件,在JAVA虚拟机运行时的数据结构,以及class相关的内容,如Method,Field道理上都与永久代一样,只是划分上更趋于合理。metaspace使用的本地内存而不是JVM内存,因此理论上可以扩展到和本地剩余内存一样大。
(3)当Perm Space中加载的类过多时候,或者存储的内部字符串过多,空间不足时候都可能会导致java.lang.OutOfMemoryError: PermGen space。

8.分派:静态分派与动态分派。

(1)上面第二个问题,讲过了
(2)静态分派:同样是将编译期确定的调用,重载(Oveload)就是这种类型,在编译期通过参数的静态类型(注意不是实际类型)作为判断依据,找到具体的调用的方法。

public class TestOverLoad {
    public static void main(String[] args) {
        //静态类型都是Parent,实际类型分别是Sun和Daughter
        Parent 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, Parent

(3)动态分派:运行期根据实际类型确定方法执行版本的分派过程称为动态分派。重写(Override),在运行时期,通过判断实体的真实类型,判断具体执行哪一个方法。

public class TestOverride {
    public static void main(String[] args) {
        //静态类型都是Parent,实际类型分别是Sun和Daughter
        Parent 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 {
        @Override
        public void testMethod() {
            System.out.println("hello, Sun");
        }
    }
    static class Daughter extends Parent {
        @Override
        public void testMethod() {
            System.out.println("hello, Daughter");
        }
    }
}
//输出
hello, Sun
hello, Daughter

9.请解释StackOverflowError和OutOfMemeryError的区别?

(1)当一个线程启动的时候,jvm就会给这个线程分配一个栈,随着程序的执行,会不断执行方法,因此栈帧会不断入栈和出栈。然后,一个栈所能容纳的栈帧是有限的,当栈帧的数量超过了栈所允许的范围的时候(比如递归调用),就会抛出StackOverflowError异常。
(2)程序在执行的过程中,需要不断的在堆内存new对象,每new一个对象,就会占用一段内存,当对没有足够的内容分配给对象示例时,就会抛出OutOfMemeryError异常。

10.你有没有遇到过OutOfMemory问题?你是怎么来处理这个问题的?处理过程中有哪些收获?

(1)读取文件时,每条数据对应一个实体,创建大量的实体,实体放入集合中,达到一定程度后,又无法通过GC回收被占用的内存,最终超过配置的内存大小,则会抛出OutOfMemeryError。
(2)从数据库中取出大量数据,每条数据一个实体,实体放入集合中,达到一定量级,超过配置的内存大小,会抛出OutOfMemeryError。
(3)实际上就一个根本原因,集合使用的内存超过了分配的最大内存了。这个时候有两种方案,分别是扩展分配的最大内存,使程序的集合能够分配到足够的内存,这种情况不推荐,治标不治本,下次集合占用的更多,还是会抛出OutOfMemeryError;另一种方案,使针对集合拆分,例如读取文件,每次读取200条,处理完成后,原来的集合设置null,重新创建新的集合,重新加入200条,这样GC的时候就可以释放掉已经处理完的实体集合。数据库读取大量数据建议分页处理,每次处理几十条,几百条即可。

感谢各位的阅读,帮忙点赞,感谢各位。

相关文章

网友评论

      本文标题:JAVA面试汇总(四)JVM(二)

      本文链接:https://www.haomeiwen.com/subject/hcidhrtx.html