【java基础 7】java内存区域分析及常见异常
本篇博客,主要是读书笔记总结,还有就是结合培训分享的总结,没有太多的技术含量!
java 的自动内存管理机制,使得程序员不用为每一个new惭怍的对象写配对的delete/ free代码(回想起C++的编写析构函数,还是挺亲切的)因为内存由虚拟机管理,所以,一旦出现了内存泄漏和溢出等问题,刚好又不了解虚拟机是怎样使用内存的,那排错工作将会变得比较艰难!
一、内存分配
Program counter register:一块比较小的内存空间,作用可以看做是当前线程所执行的字节码的行号指示器。如果线程正在执行的是一个java方法,计数器记录的是正在执行的虚拟机的字节码指令的地址,如果正在执行的是native方法,计数器值设置为空(Undefined) 备注:这是唯一一个在java虚拟机规范中没有规定任何outofmemoryerror的区域。
——详细了解计数器,可以看看CPU阿甘系列文章。
栈:
1,java virtual machine stacks:描述java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(stack frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧的在虚拟机中的入栈和出栈过程。这个区域是线程私有的,它的生命周期和线程相同。
线程私有:java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时候,一个处理器(对于多核即指一个内核)只会执行一条线程中的指令,因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,我们称这类内存区域为“”线程私有“”的内存。 ——PS:看吧,别以为多线程就一定能提高效率,说的好像切换不需要时间,程序计数器不耗性能似的。(额,看情况哈)
2,native method stacks:与java虚拟机栈相似,区别是:虚拟机栈为执行java方法(字节码)服务,而本地栈则是为虚拟机使用到的native方法服务。
注意:栈区抛出的异常一般有:stackoverflowerror和outofmemoryerror
堆:所有的对象实例以及数组都要在对上分配,原文:the heap is the runtima data area from which memory for all class instances and arrays is allocated.
由于收集器基本采用分代收集算法,所以java heap可分为新生代和老年代,再细致的分。。。。。。。。
一般来说,如果在堆中没有内存完成实例的分配,并且堆也无法再扩展时,将会抛出outofmemoryerror异常
方法区:
1,method area:是各个线程共享的内存区域(与堆一样)它用于存储已经被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。在这个区域里面,不需要连续的内存、可以选择固定大小、可扩展,可选择不实现垃圾收集。当方法区无法满足内存分配需求时,将抛出outofmemoryerror异常。
2,runtime constant pool,它属于方法区的一部分,class文件除了有类的版本、字段、方法、接口等信息,还有一项是常量池:用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。 PS:区别class文件中的常量池和运行时常量池。 当常量池无法再向方法区内存申请到内存,抛出outofmemoryerror异常。
二、一般问题解决思路
总体说来,JVM的异常,大体分为两个部分:outofmemoryerror(内存溢出) 和 stackoverflowerror(堆栈溢出)从上述文章来看,异常可以极端简化为两种情况:1,操作系统没有给JVM(各个区)足够的内存——调整JVM的内存大小可解决,通过设置相应参数;2,JVM没有给程序足够的内存——一般而言JVM不会拒绝分配内存,一旦没有足够的内存,那么就是内存用尽,即有程序劫持了空间不释放,改代码。
要想解决问题,先写出以下几段代码先:
2.1,写出一段会造成堆区溢出的代码
分析:堆区存储的是对象实例,所以,要造成堆区溢出,那么就无限制的new出对象实例吧,然后为了防止GC工作,再将这些对象实例,添加到list数组中,这样就。。。。
public class heapOOM{ static class OOMObject{ } public static void main(String[] args){
List<OOMObject> list=new ArrayList<OOMObject>(); while(true){
list.add(new OOMObject);
}
}
}
2.2,写出一段会造成栈区溢出的代码
分析:
java虚拟机栈描述java方法执行时的内存模型,如果一个方法不停的调用自己(递归)当深度达到JVM所允许的最大深度时,出错!
public class javaVMStackSof{ private int stackLength=1; public void stackLeak(){
stackLength++;
stackLeak();
} public static void main(String[] args){
javaVMStackSof oom=new javaVMStackSof(); oom.stackLeak(); }
}
本地方法栈为native方法服务,所以要溢出的话,也是通过递归使用native方法!
2.3,写出一段方法区溢出的代码
方法区是被各个线程共享的内存区域,用于存储被虚拟机加载的类信息等,所以,只要在运行时不停地加载类文件等,就会导致方法区溢出——增强class
public class javamethodareaoom{ public static void main(String[] args){
while(true){
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor(){
public Object intercept(Object obj,Method method,Object[] args,MethodProxy proxy)throws Throwable{
return proxy.invokeSuper(obj,args);
}
});
enhancer.create();
}
}
static class OOMObject{ }
}
2.4,写出一段常量池溢出的代码
只要新的常量请求不到方法区的内存,就会出错,那么最简单直接的方式,就是在运行时不停的请求内存咯!最常用的就是string.intern()方法
public class juntimeconstantpooloom{ public static void main(String[] args){
List<String> list=new ArrayList<String>();
int i=0;
while(true){
list.add(String.valueOf(i++).intern());
} }
}
三、总结
这是基本的内存分布分析,知道了怎么写代码会造成内存溢出或者内存消耗,那么当想要去优化的时候,就会轻松很多!在写这个博客的时候,突然想起了我有一次去面试的面试题,唉,现在了解了内存分配之后,才发现我当时做的关于堆栈创建对象的题,好像都错了!
不过,知识本身就是在不断的更新、更正的,现在知道错了,也不算晚,多积累,多学习吧!
【java基础 7】java内存区域分析及常见异常的更多相关文章
- Java基础一篇过(八)常见异常速查
一.引言 开发过程中可能会遇到各种各样的异常,这里还是汇总一些比较典型的异常,有些比较直观的异常如空指针这种就不写了,此文可作为异常速查用. 二.异常大军正在来袭~ IllegalArgumentEx ...
- [转]使用Java Mission Control进行内存分配分析
jdk7u40自带了一个非常好用的工具,就是Java Mission Control.JRockit Misson Control用户应该会对mission control的很多功能十分熟悉,JRoc ...
- Java虚拟机--Java内存区域的划分和异常
Java内存区域的划分和异常 运行时数据区域 JVM在运行Java程序时候会将内存划分为若干个不同的数据区域. 程序计数器 线程私有.可看作是当前线程所执行的字节码的行号指示器,字节码解释器的工作是通 ...
- Java内存区域的划分和异常
Java内存区域的划分和异常 运行时数据区域 JVM在运行Java程序时候会将内存划分为若干个不同的数据区域. 打开百度App,看更多美图 程序计数器 线程私有.可看作是当前线程所执行的字节码的行 ...
- Java基础技术-Java其他主题【面试】
Java基础技术-Java其他主题[面试] Java基础技术IO与队列 Java BIO.NIO.AIO Java 中 BIO.NIO.AIO 的区别是什么? 含义不同: BIO(Blocking I ...
- 黑马程序员:Java基础总结----java注解
黑马程序员:Java基础总结 java注解 ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! java注解 lang包中的基本注解 @SuppressWarnings ...
- Java基础:Java的四种引用
在Java基础:java虚拟机(JVM)中,我们提到了Java的四种引用.包括:强引用,软引用,弱引用,虚引用.这篇博客将详细的讲解一下这四种引用. 1. 强引用 2. 软引用 3. 弱引用 4. 虚 ...
- java基础-学java util类库总结
JAVA基础 Util包介绍 学Java基础的工具类库java.util包.在这个包中,Java提供了一些实用的方法和数据结构.本章介绍Java的实用工具类库java.util包.在这个包中,Java ...
- java基础(二)-----java的三大特性之继承
在<Think in java>中有这样一句话:复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情.在这句 ...
随机推荐
- Java编程简介
作者:CHAITANYA SINGH 来源:https://www.koofun.com//pro/kfpostsdetail?kfpostsid=3 JAVA由Sun Microsystems In ...
- java错误笔记
错误1. Description Resource Path Location Type The superclass "javax.servlet.http.HttpSer ...
- 高性能Javascript总结
一.加载和运行 Javascript代码执行会阻塞其他浏览器处理过程.充分利用webpack或gulp工具对文件打包压缩,减少js文件的数量,从而减少http请求的次数,以提高网页应用的实际性能. 二 ...
- 20170308web作业1
代码20170308001: <%@ page language="java" import="java.util.*" pageEncoding=&qu ...
- Linux下环境搭建(二)——jenkins+gitlab配置
配置jenkins+gitlab环境,需要依托java环境,在之前的博文中,已配置好java环境,所以可以直接搭建这两个工具的环境即可. jenkins配置 jenkins的配置方法,在之前windo ...
- java 删除字符串最后一个字符的几种方法
偶然看到的,记录一下,以免忘记 字符串:string s = "1,2,3,4,5," 目标:删除最后一个 "," 方法: 1.用的最多的是Substri ...
- Git强制pull
git fetch --all git reset --hard origin/master
- iOS图片目录批量复制到android图片目录
复制shell脚本 #!/bin/bash for i in `ls` do for imgname in `ls $i | grep '^WM.*'` do echo $imgname cp $i/ ...
- SQLite - WHERE子句
SQLite - WHERE子句 SQLite WHERE子句用于指定一个条件同时抓取数据从一个表或多个表. 如果给定的条件满意,意味着true,然后从表中返回特定值.你会使用WHERE子句来筛选记录 ...
- monkeyrunner之控件ID不存在或重复(转载lynnLi)
我们在用monkeyrunner进行Android自动化时,通过获取坐标点或控件ID进行一系列操作.由于使用坐标点时,屏幕分辨率一旦更改,则代码中用到坐标的地方都要修改,这样导致代码的复用率较低.因此 ...