加入收藏 | 设为首页 | 会员中心 | 我要投稿 河北网 (https://www.hebeiwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长百科 > 正文

浅谈假造机内存区

发布时间:2019-04-10 18:36:45 所属栏目:站长百科 来源:Wooola
导读:1. Java 假造机内存区概述 我们在编写措施时,常常会碰着OOM(out of Memory)以及内存走漏等题目。为了停止呈现这些题目,我们起首必需对JVM的内存分别有个详细的熟悉。JVM将内存首要分别为:要领区、假造机栈、当处所法栈、堆、措施计数器。 2. Java 假造
副问题[/!--empirenews.page--]

 1. Java 假造机内存区概述

我们在编写措施时,常常会碰着OOM(out of Memory)以及内存走漏等题目。为了停止呈现这些题目,我们起首必需对JVM的内存分别有个详细的熟悉。JVM将内存首要分别为:要领区、假造机栈、当处所法栈、堆、措施计数器。

2. Java 假造机运行时数据区

2.1. 运行时数据区分别

2.1.1 运行时数据区图

浅谈假造机内存区

2.1.2 运行时数据区包罗

  • 要领区(Method Area)
  • 假造机栈(VM Stack)
  • 当处所法栈(Native Method Stack)
  • 堆(Heap)
  • 措施计较器(Program Counter Register)

2.2. 要领区(Method Area)

2.2.1 要领区的观念

要领区又叫静态区,存放的是已加载的类的根基信息、常量、静态变量等。它是各个线程共享地区。

例如说我们在写Java代码时,每个线水平可以会见统一个类的静态变量工具。因为行使反射机制的缘故起因,假造机很难展望哪谁人类信息不再行使,因此这块地区的接纳很难。

2.2.1.1 静态块和非静态块有什么区别?

  • 类(Class)和工具(Object)的区别与接洽?
  • 为什么静态块中不能行使this、super要害字?
  • 为什么java的静态要领可以直接用类名挪用?

2.2.2 要领区的特点

线程间共享地区

2.2.3 要领区的非常

对这块地区首要是针对常量池接纳,值得留意的是JDK1.7已经把常量池转移到堆内里了。同样,当要领区无法满意内存分派需求时,会抛出OutOfMemoryError。制造要领区内存溢出,留意,必需在JDK1.6及之前版本才会导致要领区溢出,缘故起因后头表明,执行之前,可以把假造机的参数-XXpermSize和-XX:MaxPermSize限定要领区巨细。

代码清单如下:

  1. public static void printOOM() { 
  2.  List<String> list = new ArrayList<String>(); 
  3.  int i = 0; 
  4.  while (true) { 
  5.  list.add(String.valueOf(i).intern()); 
  6.  } 

输出非常功效:

  1. Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 
  2.  at java.util.Arrays.copyOf(Arrays.java:2245) 
  3.  at java.util.Arrays.copyOf(Arrays.java:2219) 
  4.  at java.util.ArrayList.grow(ArrayList.java:242) 
  5.  at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216) 
  6.  at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208) 
  7.  at java.util.ArrayList.add(ArrayList.java:440) 
  8.  at com.vprisk.knowledgeshare.MethodAreExample.main(MethodAreExample.java:15) 
  9.  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
  10.  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
  11.  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
  12.  at java.lang.reflect.Method.invoke(Method.java:606) 
  13.  at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) 

备注:网上的例子运行后会抛出java.lang.OutOfMemoryError:PermGen space非常。

2.2.3.1 关于String的intern()函数

intern()的浸染:

假如当前的字符串在常量池中不存在,则放入到常量池中。

上面的代码不绝将字符串添加到常量池,最终必定会导致内存不敷,抛出要领区的OOM。表明一下,为什么必需将上面的代码在JDK1.6之前运行。我们前面提到JDK1.7后,把常量池放入到堆空间中,这导致intern()函数的成果差异,代码清单如下:

  1. public static void testInternMethod(){ 
  2.  String str1 =new StringBuilder("hua").append("chao").toString(); 
  3.  System.out.println(str1.intern()==str1); 
  4.  String str2=new StringBuilder("ja").append("va").toString(); 
  5.  System.out.println(str2.intern()==str2); 

在场景jdk6,输出功效:

  1. false , false 

在场景jdk7,输出功效:

  1. true , false 

为什么了?

缘故起因是在JDK1.6中,intern()要了解把初次碰着的字符串实例复制到常量池中,返回的也是常量池中的字符串的引用,而StringBuilder建设的字符串实例是在堆上面,以是肯定不是统一个引用,返回false。在JDK1.7中,intern要领不再复制实例,常量池中只生涯初次呈现的实例的引用,因此intern()返回的引用和由StringBuilder建设的字符串实例是统一个。为什么对str2较量返回的是false呢?这是由于,JVM中内部在加载类的时辰,就已经有”java”这个字符串,不切合“初次呈现”的原则,因此返回false。

2.2.4 要领区的浸染

要领区存放的是类信息、常量、静态变量等,是各个线程共享地区

2.2.5 要领区的运用

通过过配置假造机的参数 -XXpermSize 以及 -XX:MaxPermSize 限定要领区巨细

2.2.6 要领区的行使场景

2.3. 假造机栈(VM Stack)

2.3.1 假造机栈的观念

假造机栈描写的是Java要领执行的内存模子:

每个要领被执行的时辰城市同时建设一个栈帧 (StackFrame)用于存储局部变量表、操纵栈、动态链接、要领出口等信息。每一个要领被挪用直至执行完成的进程,就对应着一个栈帧在假造机栈中从入栈到出栈的进程

2.3.1.1 局部变量表

局部变量表存放了编译器禁止的各类根基数据范例(boolean、byte、char、short、int、float、long、double)、工具引用(Object reference)和字节码指令地点(returnAddress范例)。

2.3.1.1 操纵栈

(编辑:河北网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读