“这是我参与8月更文挑战的第10天,活动详情查看:8月更文挑战”
引言
人要有点勇气,敢于面对不丢人,本次文章出处来源于《深入java虚拟机》,各位路见不平,要拔刀相助,每次我都拔不起刀,因为我觉得我这体格能干过坏人嘛,今天突然开悟了,我觉得不应该这么懦弱,要有勇气,要敢于直面生活中的一切,受伤的人要敢于面对,阻止施暴者继续施暴,内心的高尚才是高尚的,我知道我现在做不到,我努力做到。
方法区
我在《jvm的体系结构》一文中提到方法区,方法区的内部有一块区域是常量池,是用来存储一些我们编译时的符号引用的,因为编译的时候,编译器是找不到方法的具体位置的,故只能使用方法的符号去代替方法的位置,在解析时,将符号引用变为实际引用,也就是方法实际所在的偏移位置。
既然都是内存肯定就资源有限,肯定有内存溢出的风险。
常量池
在java中,String::intern方法的是这样定义的:如果字符串常量池中包含等于当前对象的字符串,则返回此String对象的引用,否则就会将该字符串的引用添加到常量池当中,并返回此对象的引用,那我们可以利用这一点,干一件坏事(猥琐),我们可以限制方法区的容量,然后不断更新新的引用,不断放到常量池中,就会溢出了。
但需要说明的是jDK6以前,常量池是放在永久代的,但7以后的版本是挪在了堆上,所以测试的时候要注意JDK版本,不然测试是没有意义的。
引申部分
方法区的主要职责是存储类型的相关信息的:类的类名、访问描述符、访问权限、常量池、方法描述符等等,那我们就可以使用代理帮我们生成大量的类填满我们的方法区,可别觉得这个事离我们很远,实际上,我们用的主流框架都需要用到动态代理这类技术,当我们生成的类足够多的时候,就需要足够大的方法区。
JDK8以后,永久代永远的退出了历史的舞台,元空间作为新成员加入JDK,给使用者提供了一些参数来预防此类事件的发生:
- -XX:
MaxMetaspaceSize:设置元空间大小。默认-1 - -XX:
MetaspaceSize: 指定元空间初始大小。以字节为单位,达到该值触发垃圾收集进行类型卸载,同时收集器会动态调整,如果释放了大量空间,会降低该值,反之提高但不会超过设置的元空间最大的大小。
题外话
被文字记录下来的文化历史,会永久的封存在记录的史册当中,而那些没有记录下来的,并随着历史遗迹消失的古老文明就像那些远远望去看不到的浮尘,漂浮在不可知的永远里,漠视着人类的愚昧和无知。