精华内容
下载资源
问答
  • 如果应用程序要使用动态内存,则首先要在内存中划分出可进行动态分配的区域,这个划分出来的区域叫做内存分区。每个分区又要分为若干个叫做内存块的小区。μC/OS-II规定,同处一个分区的内存块的大小必须相等,而且...
  • 栈是JVM中的一块特殊的内存区域,而JVM也是操作系统创建出来的一个进程,对于每一个程序来说,内存的使用都要通过操作系统来管理,java为了让内存管理起来更加方便,在JVM启动的时候,直接从操作系统中申请一大块...

    栈内存结构

    java中的栈是什么

    • 栈是JVM中的一块特殊的内存区域,而JVM也是操作系统创建出来的一个进程,对于每一个程序来说,内存的使用都要通过操作系统来管理,java为了让内存管理起来更加方便,在JVM启动的时候,直接从操作系统中申请一大块内存,自行管理
    • JVM对申请到的一大块内存进行进一步的区域划分,其中的一块区域就叫做栈。
    • 栈内存:方法调用的时候,该方法需要的空间在栈内存分配;
      方法不调用的时候不会再栈中分配空间的
      方法只有在调用的时候才会分配空间,并且调用的时候就是压栈
      方法执行结束之后,该方法所需要的空间就会释放,此时发生弹栈动作
    • 方法调用叫做:入栈,压栈。分配空间;
    • 方法结束叫做:出栈,弹栈。释放空间;

    栈内存的图示

    在这里插入图片描述

    栈内存的特点:

    	1、先进后出原则;
    	2、处于栈顶的元素具有活跃权
    	3、栈帧永远只主指向的是栈顶部的元素;
    

    方法调用的过程

    我们在main方法中调用fun1方法,并在fun1方法中调用fun2方法,
    每个方法都进行了开始和结束的提示。

    public class MethodTest01 {
        public static void main(String[] args) {
            System.out.println("main begin");
            fun1();
            System.out.println("main over");
        }
    
        public static void fun1() {
            System.out.println("fun1 begin");
            fun2();
            System.out.println("fun1 over");
        }
    
        public static void fun2() {
            System.out.println("fun2 begin");
            System.out.println("fun2方法正在执行");
            System.out.println("fun2 over");
        }
    }
    
    

    运行结果

    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • Dalvik虚拟机用来分配对象划分为两部分,一部分叫做Active Heap,另一部分叫做Zygote Heap。下面基于管理机制来介绍为何分配为这两部分,以及堆内存的管理。  我们从Android系统启动说起。  Android系统启动...

      Dalvik虚拟机用来分配对象的堆划分为两部分,一部分叫做Active Heap,另一部分叫做Zygote Heap。下面基于管理机制来介绍为何分配为这两部分,以及堆内存的管理。

      我们从Android系统启动说起。

      Android系统启动后,会有一个Zygote进程创建第一个Dalvik虚拟机,它只维护了一个堆。以后启动的所有应用程序进程是被Zygote进程fork出来的,并都持有一个自己的Dalvik虚拟机。在创建应用程序的过程中,Dalvik虚拟机采用COW策略复制Zygote进程的地址空间。

      COW策略:一开始的时候(未复制Zygote进程的地址空间的时候),应用程序进程和Zygote进程共享了同一个用来分配对象的堆。当Zygote进程或者应用程序进程对该堆进行写操作时,内核就会执行真正的拷贝操作,使得Zygote进程和应用程序进程分别拥有自己的一份拷贝,这就是所谓的COW。因为copy是十分耗时的,所以必须尽量避免copy或者尽量少的copy。

      为了实现这个目的,当创建第一个应用程序进程时,会将已经使用了的那部分堆内存划分为一部分,还没有使用的堆内存划分为另外一部分。前者就称为Zygote堆,后者就称为Active堆。这样只需把zygote堆中的内容复制给应用程序进程就可以了。以后无论是Zygote进程,还是应用程序进程,当它们需要分配对象的时候,都在Active堆上进行。这样就可以使得Zygote堆尽可能少地被执行写操作,因而就可以减少执行写时拷贝的操作。在Zygote堆里面分配的对象其实主要就是Zygote进程在启动过程中预加载的类、资源和对象了。这意味着这些预加载的类、资源和对象可以在Zygote进程和应用程序进程中做到长期共享。这样既能减少拷贝操作,还能减少对内存的需求。

      类似于JVM,Dalvik虚拟机也需要负责对堆内存中的对象进行管理工作,它使用的也是标记清除算法,但是细节上略有区别。

      Mark-Sweep算法分为两个阶段:

    • Mark阶段:通过递归对象的引用,从对象的根集开始标记被引用的对象。
    • Sweep阶段:回收没有被标记的对象占用的内存。

      Dalvik虚拟机通过Heap Bitmap来标记标记对象有没有被引用。所谓Heap Bitmap就是一个unsigned long数组,如果一个对象被引用,那么在Bitmap中与它对应的那一位就会被设置为1。否则的话,就设置为0。Dalvik使用了两个Bitmap来描述堆的对象,一个称为Live Bitmap,另一个称为Mark Bitmap。Live Bitmap用来标记上一次GC时被引用的对象,也就是没有被回收的对象,而Mark Bitmap用来标记当前GC有被引用的对象。这样只需要回收上一次被引用,当前未被引用的对象就可以了。

      在垃圾收集的Mark阶段,要求除了垃圾收集线程之外,其它的线程都停止(Stop The World),否则如果对象在GC过程中又引用了其他对象,就会可能导致不能正确地标记每一个对象。然而,这将造成程序卡顿,效率降低。所以必须允许在Mark阶段使垃圾回收线程和其他线程可以并发执行(Concurrent GC)。

    为了实现此目的,Dalvik将Mark阶段划分为两步:

    •   第一步,只标记根集对象,即在GC过程开始的时刻,那些被全局变量,栈变量,寄存器对象引用的对象。这个阶段只允许GC线程运行,防止这些根集对象在这个过程中再去引用其他对象。
    •   第二步,通过这些根集对象引用关系,可以找到并标记其他正在使用的对象。这个阶段可以允许其他线程与GC线程并发执行。为了实现GC线程与其他线程并发,需要把其他线程对对象的修改记录下来,记录这些修改的数据结构被称为Card Table。

      Dalvik虚拟机进行部分垃圾收集时,实际上就是只收集在Active堆上分配的对象。因此对Dalvik虚拟机来说,Card Table就是用来记录在Zygote堆上分配的对象在部收垃圾收集执行过程中对在Active堆上分配的对象的引用。

      与Bitmap不同,Card Table中每个card大小为一个字节,如果与它对应的对象在第二步未被修改过,其值为clean,否则为dirty。对于被修改过的对象,在第二步结束后需要重新使用GC线程排他地对这些对象进行标记。由于这些对象不是很多所以这个过程很快,这也是分两步的原因。

     

    转载于:https://www.cnblogs.com/cqumonk/p/4682699.html

    展开全文
  • java内存初探(一)

    2021-01-10 16:44:39
    我们写出来的程序文件后缀都是.java,比如我论文的项目后缀就全都是.java, 具体的名称叫做java源码文件。源码文件是无法被java虚拟机识别的,所以必须要用java compiler(java编译器)编译成字节码文件(.class),...

    讲道理,这个java虚拟机我感觉自己学的超级差劲,但是呢,面试又重点考察这个,所以手写一次加深印象吧。

    一、区域划分
    主要划分为堆(包括方法区),栈,本地方法栈,程序计数器

    二、java程序的具体执行过程
    我们写出来的程序文件后缀都是.java,比如我论文的项目后缀就全都是.java,具体的名称叫做java源码文件。如下图所示:

    在这里插入图片描述
    源码文件是无法被java虚拟机识别的,所以必须要用java compiler(java编译器)编译成字节码文件(.class),这.class实际上是二进制的数据,但是为什么叫字节码文件呢?我搜了一下,字节码文件长这样。
    在这里插入图片描述
    行吧,两个16进制放一起就是一个子节,好像还有计算机组成原理方面的知识,说是计算机能够处理的最小内存单位是子节,哦,反正我计算机组成原理没学好,你说啥就是啥。继续继续!!

    现在的.class文件就可以被java虚拟机识别了(必须经过java虚拟机处理之后才能成为机器码被硬件识别),不过第一步是用类加载器将.class文件先读入内存中,而不是直接在内存中处,那我就明白了,原来刚才的java compiler是先读取了.java文件,将它处理成.class文件后放回了硬盘的某处,这中间涉及了两次io操作,我记得我用idea的时候,每次运行都会出现target文件夹,应该就是存放.class文件的地方,然后点clean就没了,下次再次运行的时候就会再次编译,这好麻烦啊,写到这里,我又来一个新问题了,如果我不点clean但是改动了.java文件,那么它下次再运行的时候是会运行原来已经编译好的.class文件呢,还是再次编译呢?我觉着java虚拟机不会那么聪明知道我有没有改动,所以它应该是每次运行都重新编译,这可真麻烦啊,吐槽结束,继续继续!

    .class读入内存中总得有个地方放它呀,java虚拟机给它弄了个方法区给它呆着,深入理解jvm这本书说方法区是各个线程共享的区域,既然是各个线程共享,那我觉着静态方法静态变量和常量肯定在里面,一查果然在哈哈,当然里面还放了类的信息(类名,方法信息,字段信息(简单来说就是变量?包括了这个变量的名字,类型和修饰符(public、protected和private))),这些东西似乎不太需要垃圾回收吧?所以有人喜欢把它叫做永久代,嗯,古人诚不欺我。

    然后再谈谈刚才说到的类加载器(classloader),我原本以为它只有一个,结果后来人家说有三个,分别是bootstraploader extclassloader 和appclassloader
    bootstrap class加载器是用c++语言写的,java虚拟机一启动这玩意就初始化了,是最核心的加载器,它可以加载%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。我来查查这些玩意下面都是个啥在这里插入图片描述
    在这里插入图片描述
    可以看到有sql包,lang包,io包和math包,这些都是我们很熟悉的东西,嗯,不愧是核心包。

    extension classloader是扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。还可以加载-D java.ext.dirs选项指定的目录。这个我也来查查是个啥吧在这里插入图片描述
    哦,不认识,那就这样吧。

    第三个加载器是appclassloader 这玩意也称为systemappclass,用来加载当前应用的classpath的所有类。也就是说我们自己写的类基本上都是由这玩意加载的。

    这地位一看就是bootstraploader老大,extclassloader老二appclassloader老三啊,然后上网一查,appclassloader的父加载器是extclassloader,而extclassloader的父加载器是空,这不对啊,明明人家说extclassloader的爹是bootstraploader!再仔细一看,bootstraploader是由c++写的,我们是高贵的c++,你还想让我当你低贱的java中的一员?你整个java的类加载器都是我生的!!!
    那行吧,那串一下就是,bootstraploader 生成了extclassloader,extclassloader生成了appclassloader

    然后类加载也是有讲究的,一个类加载器查找class和resource时,是通过委托模式进行的,它首先判断这个class类是否已经加载成功,如果没有,那么它自己先不干活,而是让他爹去进行查找,这妥妥的啃老族好吧,那最老的那个是谁?高贵的c++写的bootstraploader啊!我觉着它心里肯定很苦,凭啥我没爹?那没爹坑只能自己干呗,如果它找到了,那么就直接返回,如果没找到,再让它儿子去找,直到回到最开始啃老的那个儿子去查找这些对象,这种机制就叫做双亲委托,这里我又得吐槽一波了,双亲明明是爸妈好吧,你这叫爹爷委托!!!
    那为啥写jvm的那群人要助长这种啃老之风呢?我去网上扒了一下:

    采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。
    原来是这样,行吧,你说的对,我继续。

    classloader会将编译阶段的.class文件加载到jvm内存中去,这个阶段会经过装载,连接和初始化的过程。

    我写累了,要休息了,晚上再写接下来的嘻嘻。

    展开全文
  • 对象的创建:虚拟机遇到一个new关键字时,先会去常量池中检查是否有这个类的...1如果java堆中的内存是规整的左边我们叫做A区域,存放已经使用过的内存,右边我们叫B区域,存放着还没使用的内存区域,中间放着指示器...

    对象的创建:虚拟机遇到一个new关键字时,先会去常量池中检查是否有这个类的符号引用,并检查这个类所代表的类是否已经被加载,解析,初始化如果没有,那就必须先进行相应的类加载过程。在类加载过程通过后,接下来将为新生的对象分配内存(从java堆中划分出来一片内存区域出来)。

    1如果java堆中的内存是规整的左边我们叫做A区域,存放已经使用过的内存,右边我们叫B区域,存放着还没使用的内存区域,中间放着指示器,只需要将指示器向右边挪动一小段,这种方式我们称作指针碰撞。

    2如果java堆中内训区域是分散的,那就不能进行简单的指针碰撞,虚拟机必须维护一个列表,记录那些内存块是可用的,在分配的时候找到足够大的一块分配给对象实例,并更新列表上的记录,这种分配方式成做空闲列表。

    选择以上那种方式由java堆是否规整决定,而java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。

    对象的创建在jvm中是一个非常频繁的过程,有可能正在给对象A分配内存,指针好美来的及进行修改,对象B又同时使用了原来的指针进行分配内存,这样子是非常不安全的,解决这种问题有两个方案。

    1是对分配内存的动作进行同步处理---采用CAS配上失败重试来保证更新操作的原子性。

    2将内存分配的动作按照线程划分在不同的空间中进行,即每个线程在java堆中预先分配一小块内存,成为本地线程分配缓冲。

    内存分配完成时,虚拟机需要将分配到的空间都初始化为0,接下来需要对创建的对象进行一定的标识,例如这个对象是那个类的实例,如何才能找到类的元数据信息,对象的哈希码,对象的GC分代年龄等等,这些信息存放在java对象投之中。

    在上面的工作都完成之后,从虚拟机的角度来看,一个新的对象已将产生了,但是从java程序的角度来看,对象的创建才刚刚开始,<init>方法还没有执行,多有的字段还为0,执行new指令之后,然后会紧接着执行init方法,

    展开全文
  • Java把内存分成两种,一种叫做内存,一种叫做内存:在执行过程中会划分4个内存区域(heap、stack、data segment、code segment)。 java开始执行会把代码加载到code segment区域然后找到main方法开始执行; heap...
  • 为对象分配内存就是在堆中把一块确定大小的内存划分出来。这时候会有一个问题:java堆是否规整 如果堆规整,所有用过的内存放在一边,没用过的内存放在另一边,中间放一个指针作为分界线。这时候分配内存就是讲...
  • 对象加载过程

    2020-06-07 23:25:49
    为对象分配空间,把一块固定大小的内存从java堆里划分出来。如果java堆是那种齐整的,一边放已经用的内存,另一边放没有用的内存,这样就有一个中间指针隔开两个区域,只要把这个指针移动到相应位置即可,这种方法...
  • JAVA中native方法调用C语言实现学习

    千次阅读 2016-06-20 21:43:46
    在java虚拟机规范的内存管理划分中,对于虚拟机内存空间划分中专门划了一块内存叫做“本地方法栈(Native Method Stack)”。本地方法栈是为了java专门用来调用native方法而划分出来的一块内存。 我们平时在阅读...
  • 1.java虚拟机的基本结构 ...栈:存放局部变量,线程私有的,描述的是java方法执行的内存模型:每个方法在执行时都会创建一个栈帧,用户存储局部变量表,操作数栈,动态连接,方法出口等信息。每一个方法从
  • 相当于把一块确定大小的内存从Java堆中划分出来。指针碰撞(Bump the Pointer)假设将堆划分为两部分,左边为已使用内存,右边为空闲内存。(堆内存规整)在左边和右边的中间放一个指针作为指示器,这样将指针右移与...
  • IO流入门-概述

    2017-04-12 15:28:00
    按方向划分:输入流和输出流,是相对内存而言。从内存出来是输出,到内存中就是输入。输入流又叫做InputStream,输出流叫OutputStream。输入还叫做“读Read”,输出还叫做“写Write”。 按读取数据方式划分:...
  • Java心得

    2019-06-09 22:35:22
    把这new出来的对象叫做实例。 变量和方法又是什么? 变量就是可以被改变的数据。方法是JAVA创建一个有名字的子程序的方法。 static修改的变量有什么特点? 它来修饰成员变量用或方法的时候,就可直接用“类名.方法”...
  • 了解JVM快速入门+jvm性能调优详解

    千次阅读 2018-01-26 10:07:39
    1.java虚拟机的基本结构总结:jvm内存结构也叫做运行时数据区,堆和方法区是全局共享的,栈,程序计数器和本地方法栈是线程私有的具体划分为如下5个内存空间:(非常重要)堆:存放所有new出来的东西,堆空间是所有...
  •  GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收...
  • JVM之常用配置参数

    2019-01-19 15:17:15
     无监控不调优:如果没有一个评价系统性能手段,则调优没有意义,因为你改了参数以后测试不出来  Java虚拟机调优主要涉及堆内存的调整和垃圾收集调整 Java内存区域划分  方法区:在Java8以后叫做永久区,...
  • JVM性能调优

    千次阅读 2018-07-01 22:39:45
    JVM调优无监控不调优:如果没有一个评价系统性能手段,则调优没有意义,因为你改了参数以后测试不出来Java虚拟机调优主要涉及堆内存的调整和垃圾收集调整Java内存区域划分方法区:在Java8以后叫做永久区,存放...
  • 虚存是由操作系统调度,采用内外存交换技术,各道程序在必需使用时调入内存,不用调出内存,这样好象内存容量不受限制。 虚存特点: (1)虚存容量不是无限,极端情况受内存和外存可利用总...
  • 叫做空壳app 业务组件: 最上层业务,每个组件表示一条完整业务线,彼此之间互相独立。 该案例中分为:干活集中营,玩Android,知乎日报,微信新闻,头条新闻,搞笑视频,百度音乐,我记事本,豆瓣...
  • 其程序结构是按功能划分为若干个基本模块;各模块之间关系尽可能简单,在功能上相对独立;每一模块内部均是由顺序、选择和循环三种基本结构组成;其模块化实现具体方法是使用子程序。结构化程序设计由于采用了...
  • java 面试题 总结

    2009-09-16 08:45:34
     GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收...
  • 软件工程教程

    热门讨论 2012-07-06 23:10:29
    UML是“三人帮”“捣”出来的 迭代开发过程这样流转 软件工程水平是这样提高的 敏捷开发过程-Scrum 送餐管理系统--用例图 送餐管理系统--类图 送餐管理系统--顺序图 任务1 软件工程 软件的定义及其特点 软件...
  • oracle框架主要由物理结构、逻辑结构、内存分配、后台进程、oracle例程、系统改变号 (System Change Number)组成  物理结构 物理结构包含三种数据文件: 1) 控制文件 2) 数据文件 3) 在线重做日志文件  ...

空空如也

空空如也

1 2
收藏数 23
精华内容 9
关键字:

划分出来的内存叫做