技术标签: 架构之路 JVM & JDK
JVM在运行过程中会把它所管理的内存划分成若干不同的数据区域。
主要存放指令
)主要存放数据
)程序计数器是用于存放下一条指令所在单元的地址的地方。
我们可以随意拿一个class
文件进行反编译,看看其结构。
如下,JvmDemo.class
文件:
cafe babe 0000 0033 0045 0a00 1000 2608
0027 0900 0f00 2808 0029 0900 0f00 2a0a
002b 002c 0900 2d00 2e07 002f 0a00 0800
260a 0008 0030 0a00 0800 310a 0032 0033
...
TIP
: javap
是 Java class文件分解器,可以反编译(即对javac编译的文件进行反编译),也可以查看java编译器生成的字节码。用于分解class文件。
执行javap -v ./JvmDemo.class > JvmDemo.txt
,将JvmDemo.class
文件分解为JvmDemo.txt
:
其左侧的序号就是所谓的程序计数器
,用于确定代码的执行顺序。
当前线程
运行方法所需的数据、指令、返回地址。栈
这个数据结构的特性就是先进后出
。虚拟机栈主要存放的是栈帧
。
类中每一个方法对应一个栈帧。通俗的说,可以将程序调用的一个方法看做一个栈帧
。
栈帧可以划分为四个结构:
StackOverflowError
当线程调用一个方法,就会产生一个栈帧
,存储在栈中。若是方法的内部还有方法调用的话,那就会有新的栈帧
存放在栈中,成为栈顶元素
。
如线程对下面方法的调用:
public void A(){
B();
...其他操作
}
public void B(){
C();
...其他操作
}
}
public void C(){
...其他操作
}
那么其虚拟机栈
的情况如下:
从结构上来看,在栈帧C未出栈时,A和B方法是无法取出的。所以A和B方法必须等待C方法的执行。
从上图也可以看出,若是有某个方法是无限递归
的话,那么虚拟机栈
只有入栈,没有出栈。就会导致栈内存溢出。(栈默认大小是 1M
)
如下无限递归调用recursion()
方法:
/**
* @author wangcw
* @create 2019-05-08 21:16
* @description:测试栈溢出
**/
public class JvmDemo {
private static int stackLength = 0;
public static void recursion(){
stackLength++;
recursion();
}
/* 测试递归调用,让 栈内存溢出 */
public static void main(String[] args) {
try{
recursion();
} catch (Throwable e){
System.out.println("出现异常,递归调用次数(即栈的长度):" + stackLength);
e.printStackTrace();
}
}
}
默认情况下调用结果:
出现异常,递归调用次数(即栈的长度):11907
java.lang.StackOverflowError
尝试修改一下栈的大小为2M( -Xss2M
),再启动:
出现异常,递归调用次数(即栈的长度):27266
java.lang.StackOverflowError
可以看出,当出现栈溢出的错误时,一般不是更改栈大小能解决的,通常情况下都是循环递归代码导致的。
一般是递归死循环,导致栈帧过多,虚拟机棧已经存放不下去了,就会出现栈溢出的情况。
OutOfMemoryError
不同于StackOverflowError,OutOfMemoryError指的是当整个虚拟机栈内存耗尽,并且无法再申请到新的内存时抛出的异常。JVM未提供设置整个虚拟机栈占用内存的配置参数。虚拟机栈的最大内存大致上等于“JVM进程能占用的最大内存。
当虚拟机栈能够使用的最大内存被耗尽后,便会抛出OutOfMemoryError,可以通过不断开启新的线程来模拟这种异常。
**
* java栈溢出OutOfMemoryError
* JVM参数:-Xss2m
*/
public class JavaVMStackOOM {
private void dontStop() {
while (true) {
}
}
//通过不断的创建新的线程使Stack内存耗尽
public void stackLeakByThread() {
while (true) {
Thread thread = new Thread(() -> dontStop());
thread.start();
}
}
public static void main(String[] args) {
JavaVMStackOOM oom = new _03_JavaVMStackOOM();
oom.stackLeakByThread();
}
}
设置单个线程虚拟机栈的占用内存为2m并不断生成新的线程,最终虚拟机栈无法申请到新的内存,抛出异常:
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
高并发,多线程项目中。栈默认大小 1M - - >
1000线程同时运行 * 1M = 1G 。需要占用1G的空间,相当浪费。
通常情况下对虚拟机栈的优化都是将其调小
。大部分情况下,栈大小128K
基本就够了。
本地方法栈的功能和特点类似于虚拟机栈。不同的是,本地方法栈服务的对象是JVM执行的native
方法,而虚拟机栈服务的是JVM执行的java
方法。
新生代
老年代
永久代
(当JDK >= 1.8成为元空间
)
GC多次仍然存在,存活时间长
)大小在新生代放不下,因为新生代默认情况仅占有堆内存的1/3
)而方法区,即永久代
存放的内容:
复制回收算法
(Minor GC
)复制回收算法的一个缺点就是每次都需要保留50%的内存空间不使用。
按照很多互联网公司的数据统计,新生代一般有90%的对象是不需要垃圾回收的。程序员能自己处理好,仅大概有10%的对象需要去做垃圾回收。(复制回收算法
)。
上述结论也能推理出新生代中 Eden区
、From Survivor区
、To Survivor区
在新生代中的比例是 8:1:1
的原因。其中10%的From区
或者To区
是做预留空间使用的。
标记清除算法
或者标记整理算法
(Full GC
)
标记-清除算法
的缺点是清除完,内存不连续。
标记-整理算法
比标记-清除算法
多了一个整理的步骤,虽然内存空间连续了,但是效率相对要低一些。一般老年代的GC还是会优先选择标记-清除算法
。
OutOfMemoryError
内存溢出
:指的是GC已经回收不了,通常是对象过多或者过大,已经超出了启动时设置的最大堆内存,就会导致内存溢出。
尝试一下堆内存溢出,设置启动参数:-Xms5m -Xmx5m
。
-Xms:设置初始分配大小,默认为物理内存的“1/64”
-Xmx:最大分配内存,默认为物理内存的“1/4”
HeapOOM.java
/**
* @author wangcw
* @create 2019-05-08 21:16
* @description:测试堆内存溢出
**/
public class HeapOOM {
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
int i = 0;
while (true){
//无限循环
System.out.println(i++);
list.add(new Object());
}
}
}
运行后会得到结果:
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
内存泄漏
:一般是指某个对象,JVM回收不走(根据可达性分析),认为其有用,而实际上该对象是没用的,就一直占用的内存空间,导致JVM的内存空间减小,这就是内存泄漏。
Java的内存泄露
多半是因为对象存在无效的引用,对象得不到释放,如果发现Java应用程序占用的内存出现了泄露的迹象,那么我们一般采用下面的步骤分析:
heap dump
(如jmap
)Java heap
分析工具(如MAT),找出内存占用超出预期的嫌疑对象保存堆栈快照日志
分析内存泄漏
调整内存设置
控制垃圾回收频率
选择适合的垃圾回收器
TIP:在不了解JVM内存模型的情况下不要随意更改class文件,容易造成OOM。
Servlet & JSPWeb服务器做些什么Web服务器接收客户请求,然后向客户返回一些结果。如果没有请求的资源,则返回404 Not Found错误。Web客户端做些什么Web客户端允许用户请求服务器上的某个资源,并且向用户显示请求的结果。客户和服务器都知道HTML和HTTPHTML告诉浏览器怎样向用户显示内容。HTTP是Web上客户和服务器之间进行通信所
昨天去了安天的反病毒招新笔试,惨败而归! 本来抱着试试看的心里去的,也没打算真正要参加这个俱乐部,毕竟现在已经是大三了,要面临考研和找工作了,这两样哪一样都很忙的,同时还要搞好学习工作,真是让人头痛。 我现在的专业不是很喜欢,想要换一个自己喜欢的学习,所以还要学习另外一个专业的课程,这大大加重了我的负担,几乎是每天晚上都要自习很长时间,但是这样还是感觉自己的时间不够用,很多
最近互联网上比较火热的话题当然是关于WEB2.0的应用,其中AJAX又是WEB2.0的核心之一。文章来源:http://blog.csdn.net/LittleXun/archive/2007/03/27/1542208.aspx转载于:https://www.cnblogs.com/cnherman/archive/2007/12/31/1021733.html...
笔记来自课程:玩转文本挖掘(51ct0学院),总结整理为个人学习、复习使用,供参考。分词思想和工具也有很多,这里先只学习jeiba分词。jieba分词三种分词模式精确模式:试图将句子最精确分开,适合做文本分析(默认精确模式)全模式:把句子中所有可以成词的词语扫描出来,速度快,但不能解决歧义搜索引擎模式:在精确模式基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词(考虑了搜索引擎的需求,主要是为了提高搜索引擎的命中率)另外,也支持繁体分词和自定义词典基本使用import jie
栅格布局的描述:antdv官方文档介绍布局的栅格化系统,基于行(row)和列(col)来定义信息区块的外部框架,以保证页面的每个区域能够稳健地排布起来个人理解:类似于excel中的表格,一个一个的单元格可以进行合并,也可以进行拆分,只不过antd每行最多24个格子,bootstrap为12个格子,通过栅格化的系统使布局更加简单,美观。开发中的问题:在日常的开发中,在不同的分辨率下,界面布局出现错行,原来在一行上的组件,在不同的分辨率下变成了多行。原因分析:造成的此问题原因主要有两个:
HNU软件能力实训1-9. 二叉树遍历,从前序、中序到后序
今天上厕所的时候刷到别人说到面向接口编程和面向业务编程,然后就想到了接口的特性,随后想到一个接口可以有多个实现类,有多个实现类的话,控制层是怎么调用其中的实现类的呢?因为以前没遇到过这个问题,自己的实际开发中一个接口只有一个实现类,然后就想到万一一个接口有两个以上的实现类的话,控制层自动注入的实现类到底是哪一个的问题。(然后还想到,自己写的每一个项目,都是一个接口一个实现类,根本没有利用到接口设计的优点,当然这不是本题所讨论的重点,但是可以做个小标记供以后进阶学习。)下面开始介绍我网上搜集到的三种方式。
bitmap, canvas, paint 区别, 联系, 使用关系Canvas对于这个类,不熟悉, 但绝对见过!而且十分令人印象深刻的是在Android 源码中, 一个举世闻名的类–View:public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource { 此处省略一万多行代码。。。。 /*直至一处举世闻名的方法*//** * Implemen.
anaconda-navigator无法打开,一直卡在loading applications 上面的解决方法
1、官方答案Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络宽带。既然单线程容易实现,而且CPU不会成为瓶颈,那么顺理成章的采用单线程的方案。2、我的理解(1)不需要各种锁的性能消耗Redis的数据结构并不全是key-value形式的,还有list,hash等复杂的结构,这些结构有可能会进行很细粒度的操作,比如在很长的列表后面添加一个元素,在hash中添加或删除一个对象,这些操作可能就需要加非常多的锁,导致的结果是同步开销大大增加。总之,在.
Matlab火焰烟雾检测(GUI)所属分类:matlab例程开发工具:matlab文件大小:11868KB下载次数:29上传日期:2020-03-20 00:58:54上 传 者:for Matlab说明:Matlab火焰烟雾检测(GUI)本设计为基于matlab的烟雾火焰火灾识别系统,可读取视频或者图象,检测出是否有烟雾火焰,具备一个人机交互式GUI界面,功能强大,识别准确,同时配备相对应的...
导入时遇到IMP-00017,IMP-00003错误[[email protected] ~]$ cat parfile_imp.txtuserid="scott/tiger"file=/home/oracle/exp_lzl....