精华内容
下载资源
问答
  • 操作系统的主要组成部分:进程和线程的管理,存储管理,设备管理,文件管理。虚拟内存是一些系统页文件,存放在磁盘上,每个系统页文件大小为4K,物理内存也被分页,每个页大小也为4K,这样虚拟页文件和物理内存页就...

     操作系统的主要组成部分:进程和线程的管理,存储管理,设备管理,文件管理。虚拟内存是一些系统页文件,存放在磁盘上,每个系统页文件大小为4K,物理内存也被分页,每个页大小也为4K,这样虚拟页文件和物理内存页就可以对应,实际上虚拟内存就是用于物理内存的临时存放的磁盘空间。页文件就是内存页,物理内存中每页叫物理页,磁盘上的页文件叫虚拟页,物理页+虚拟页就是系统所有使用的页文件的总和。

    展开全文
  • 在很多脚本语言中,您不必担心内存如何管理的,这并不能使得内存管理的重要性有一点点降低。对实际编程来说,理解您的内存管理器的能力与局限性至关重要。在大部分系统语言中,比如 C 和 C++,您必须进行内存...
  • 不管在什么语言里,内存管理的内容都很重要,Swift使用自动引用计数来管理应用程序的内存使用。这表示内存管理已经Swift的一部分,在大多数情况下,你并不需要考虑内存的管理。本文主要介绍了Swift中内存管理的...
  • 本篇文章给大家带来的...因此,它垃圾收集器(GC)管理的主要目标。其具有以下特点: 堆在逻辑上划分为“新生代”和“老年代”。由于JAVA中的对象大部分朝生夕灭,还有一小部分能够长期的驻留在内存中,为了...

    本篇文章给大家带来的内容是关于什么是堆?什么是方法区?JVM内存模型中堆与方法区的介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

    一、堆(Heap)

    1.1.什么是堆

    堆是用于存放对象的内存区域。因此,它是垃圾收集器(GC)管理的主要目标。其具有以下特点:

    • 堆在逻辑上划分为“新生代”和“老年代”。由于JAVA中的对象大部分是朝生夕灭,还有一小部分能够长期的驻留在内存中,为了对这两种对象进行最有效的回收,将堆划分为新生代和老年代,并且执行不同的回收策略。不同的垃圾收集器对这2个逻辑区域的回收机制不尽相同,在后续的章节中我们将详细的讲解。
    • 堆占用的内存并不要求物理连续,只需要逻辑连续即可。
    • 堆一般实现成可扩展内存大小,使用“-Xms”与“-Xmx”控制堆的最小与最大内存,扩展动作交由虚拟机执行。但由于该行为比较消耗性能,因此一般将堆的最大最小内存设为相等。
    • 堆是所有线程共享的内存区域,因此每个线程都可以拿到堆上的同一个对象。
    • 堆的生命周期是随着虚拟机的启动而创建。

    img

    1.2.堆异常

    当堆无法分配对象内存且无法再扩展时,会抛出OutOfMemoryError异常。

    一般来说,堆无法分配对象时会进行一次GC,如果GC后仍然无法分配对象,才会报内存耗尽的错误。可以通过不断生成新的对象但不释放引用来模拟这种情形:

    /**
     * java堆溢出demo
     * JVM参数:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
     * Created by chenjunyi on 2018/4/25.
     */
    public class HeapOOM {
    
        static class OOMObject {
        }
    
        public static void main(String[] args) {
            List<OOMObject> list = new ArrayList<>();
            //不断创建新对象,使得Heap溢出
            while (true) {
                list.add(new OOMObject());
            }
        }
        
    }
    

    上述代码中对象不断的被创建而不进行引用释放,导致GC无法回收堆内存,最终OutOfMemoryError,错误信息:

    java.lang.OutOfMemoryError: Java heap space
    

    二、方法区(Method Area)

    2.1.什么是方法区

    方法区,也称非堆(Non-Heap),又是一个被线程共享的内存区域。其中主要存储加载的类字节码、class/method/field等元数据对象、static-final常量、static变量、jit编译器编译后的代码等数据,。另外,方法区包含了一个特殊的区域“运行时常量池”,它们的关系如下图所示:

    img

    (1)加载的类字节码:要使用一个类,首先需要将其字节码加载到JVM的内存中。至于类的字节码来源,可以多种多样,如.class文件、网络传输、或cglib字节码框架直接生成。
    (2)class/method/field等元数据对象:字节码加载之后,JVM会根据其中的内容,为这个类生成Class/Method/Field等对象,它们用于描述一个类,通常在反射中用的比较多。不同于存储在堆中的java实例对象,这两种对象存储在方法区中。
    (3)static-final常量、static变量:对于这两种类型的类成员,JVM会在方法区为它们创建一份数据,因此同一个类的static修饰的类成员只有一份;
    (4)jit编译器的编译结果:以hotspot虚拟机为例,其在运行时会使用JIT即时编译器对热点代码进行优化,优化方式为将字节码编译成机器码。通常情况下,JVM使用“解释执行”的方式执行字节码,即JVM在读取到一个字节码指令时,会将其按照预先定好的规则执行栈操作,而栈操作会进一步映射为底层的机器操作;通过JIT编译后,执行的机器码会直接和底层机器打交道。如下图所示:

    img

    2.2.运行时常量池

    在2.1小节中,我们了解到类的字节码在加载时会被解析并生成不同的东西存入方法区。类的字节码中不仅包含了类的版本、字段、方法、接口等描述信息,还包含了一个常量池。常量池用于存放在字节码中使用到的所有字面量和符号引用(如字符串字面量),在类加载时,它们进入方法区的运行时常量池存放。

    运行时常量池是方法区中一个比较特殊的部分,具备动态性,也就是说,除了类加载时将常量池写入其中,java程序运行期间也可以向其中写入常量:

    // 使用StringBuilder在堆上创建字符串abc,再使用intern将其放入运行时常量池
    String str = new StringBuilder("abc");
    str.intern();
    // 直接使用字符串字面量xyz,其被放入运行时常量池
    String str2 = "xyz";
    

    2.3.方法区的实现

    方法区的实现,虚拟机规范中并未明确规定,目前有2种比较主流的实现方式:

    (1)HotSpot虚拟机1.7-:在JDK1.6及之前版本,HotSpot使用“永久代(permanent generation)”的概念作为实现,即将GC分代收集扩展至方法区。这种实现比较偷懒,可以不必为方法区编写专门的内存管理,但带来的后果是容易碰到内存溢出的问题(因为永久代有-XX:MaxPermSize的上限)。在JDK1.7+之后,HotSpot逐渐改变方法区的实现方式,如1.7版本移除了方法区中的字符串常量池。

    (2)HotSpot虚拟机1.8+:1.8版本中移除了方法区并使用metaspace(元数据空间)作为替代实现。metaspace占用系统内存,也就是说,只要不碰触到系统内存上限,方法区会有足够的内存空间。但这不意味着我们不对方法区进行限制,如果方法区无限膨胀,最终会导致系统崩溃。

    我们思考一个问题,为什么使用“永久代”并将GC分代收集扩展至方法区这种实现方式不好,会导致OOM?首先要明白方法区的内存回收目标是什么,方法区存储了类的元数据信息和各种常量,它的内存回收目标理应当是对这些类型的卸载和常量的回收。但由于这些数据被类的实例引用,卸载条件变得复杂且严格,回收不当会导致堆中的类实例失去元数据信息和常量信息。因此,回收方法区内存不是一件简单高效的事情,往往GC在做无用功。另外随着应用规模的变大,各种框架的引入,尤其是使用了字节码生成技术的框架,会导致方法区内存占用越来越大,最终OOM。

    2.4.方法区异常

    在2.3一节中,我们了解到方法区的2种实现方式最终都会有一个最大值上限,因此若方法区(含运行时常量池)占用内存到达其最大值,且无法再申请到内存时,便会抛出OutOfMemoryError。

    在下面的例子中,我们将使用cglib字节码生成框架不断生成新的类,最终使方法区内存占用满,抛出OutOfMemoryError:

    /**
     * java方法区溢出OutOfMemoryError(JVM参数适用于JDK1.6之前,借助CGLIB)
     * JVM参数:-XX:PermSize=10M -XX:MaxPermSize=10M
     * Created by chenjunyi on 2018/4/26.
     */
    public class JavaMethodAreaOOM {
    
        public static void main(String[] args) {
            while (true) {
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(OOMObject.class);
                enhancer.setUseCache(false);
                enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> methodProxy.invokeSuper(objects, args));
                enhancer.create();
            }
        }
    
        static class OOMObject {
        }
    
    }
    

    报错信息为:

    Caused by: java.lang.OutOfMemoryError: PermGen space
      at java.lang.ClassLoader.defineClass1(Native Method)
      ···
    

    其实,在日常开发中,不仅仅使CGlib字节码生成框架会产生大量的class信息,动态语言、JSP、基于OSGI的应用都会在方法区额外产生大量的类信息。

    展开全文
  • [转]PHP的内存管理

    2015-05-11 22:03:27
    PHP的内存管理, 分为俩大部分, 第一部分PHP自身的内存管理, 这部分主要的内容就是引用计数, 写时复制, 等等面向应用层面管理. 而第二部分就是今天我要介绍, zend_alloc中描写关于PHP自身的内存管理, 包括...

         另外, 为什么要写这个呢, 因为之前并没有任何资料来介绍PHP内存管理中使用的策略, 数据结构, 或者算法. 而在我们平时开发扩展, 修复PHP的bug的时候, 却对这一部分的知识需要有一个良好的理解. PHP开发组内的很多朋友也对这块不是很清楚, 所以我觉得有必要专门写一下.

         一些基本的概念, 我就不赘述了, 因为看代码很容易能看懂, 我这里就主要介绍几个看代码没那么容易看懂的点, 为什么这么说呢, 呵呵, 我在写文章之前, 查找了下已有的资料, 已避免重复功, 其中看到了TIPI项目对这部分的描述, 我只能说, 错误很多. 所以, 我想这部分就是看代码也没那么容易看懂的点 :)

         目前, 英文版的介绍也在撰写中: Zend MM

         Zend Memory Manager, 以下简称Zend MM, 是PHP中内存管理的逻辑. 其中有一个关键数据结构: zend_mm_heap: 

         Zend MM把内存非为小块内存和大块内存俩种, 区别对待, 对于小块内存, 这部分是最最常用的, 所以追求高性能. 而对于大块内存, 则追求的是稳妥, 尽量避免内存浪费.

         所以, 对于小块内存, PHP还引入了cache机制: 

         Zend MM 希望通过cache尽量做到, 一次定位就能查找分配.

         而一个不容易看懂的点是free_buckets的申明:

         Q: 为什么free_buckets数组的长度是ZEND_MM_NUMBER_BUCKET个?

         A: 这是因为, PHP在这处使用了一个技巧, 用一个定长的数组来存储ZEND_MM_NUMBER_BUCKET个zend_mm_free_block, 如上图中红色框所示. 对于一个没有被使用的free_buckets的元素, 唯一有用的数据结构就是next_free_block和prev_free_block, 所以, 为了节省内存, PHP并没有分配ZEND_MM_NUMBER_BUCKET * sizeof(zend_mm_free_block)大小的内存, 而只是用了ZEND_MM_NUMBER_BUCKET * (sizeof(*next_free_block) + sizeof(*prev_free_block))大小的内存..

         我们来看ZEND_MM_SMALL_FREE_BUCKET宏的定义:

    #define ZEND_MM_SMALL_FREE_BUCKET(heap, index) \\
        (zend_mm_free_block*) ((char*)&heap->free_buckets[index * 2] + \\
            sizeof(zend_mm_free_block*) * 2 - \\
            sizeof(zend_mm_small_free_block))
    

         之后, Zend MM 保证只会使用prev和next俩个指针, 所以不会造成内存读错..

         那么, 第二个不容易看懂的点, 就是PHP对large_free_buckets的管理, 先介绍分配(TIPI项目组对此部分的描述有些含糊不清):

    static zend_mm_free_block *zend_mm_search_large_block(zend_mm_heap *heap, size_t true_size)
    

         large_free_buckets可以说是一个建树和双向列表的结合: 

         双向列表保持着同样size的内存块, 而左右孩子(child[0]和child[1])分别代表着键值0和1, 这个键值是指什么呢?

         我们来举个例子, 比如我向PHP申请一个true_size为0b11010大小的内存, 经过一番步骤以后, 没有找到合适的内存, PHP进入了zend_mm_search_large_block的逻辑来在large_free_buckets中寻找合适的内存:

        1. 首先, 计算true_size对应的index, 计算方法是, 获取true_size中最高位1的序号(zend_mm_high_bit), 对应的汇编指令是bsr(此处, TIPI项目错误的说明为: “这个hash函数用来计算size的位数,返回值为size二进码中1的个数-1″).

        2. 然后在一个位图结构中, 判断是否存在一个大于true_size的可用内存已经存在于large_free_buckets, 如果不存在就返回:

    size_t bitmap = heap->large_free_bitmap >> index;
    if (bitmap == 0) {
       return NULL;
    }
    

        3. 判断, free_buckets[index]是否存在可用的内存:

    if (UNEXPECTED((bitmap & 1) != 0))
    

        4. 如果存在, 则从free_buckets[index]开始, 寻找最合适的内存, 步骤如下:

         1. 从free_buckets[index]开始, 如果free_buckets[index]当前的内存大小和true_size相等, 则寻找结束, 成功返回.

         2. 查看true_size的当前最高位, 如果为1. 则在free_buckets[index]->child[1]下面继续寻找, 如果free_buckets[index]->child[1]不存在, 则跳出. 如果true_size的当前最高位为0, 则在free_buckets[index]->child[0]下面继续寻找, 如果free_buckets[index]->child[0]不存在, 则在free_buckets[index]->child[1]下面寻找最小内存(因为此时可以保证, 在free_buckets[index]->child[1]下面的内存都是大于true_size的)

         3. 出发点变更为2中所述的child, 左移一位ture_size.

        5. 如果上述逻辑并没有找到合适的内存, 则寻找最小的”大块内存”:

       /* Search for smallest "large" free block */
        best_fit = p = heap->large_free_buckets[index + zend_mm_low_bit(bitmap)];
        while ((p = p->child[p->child[0] != NULL])) {
            if (ZEND_MM_FREE_BLOCK_SIZE(p) < ZEND_MM_FREE_BLOCK_SIZE(best_fit)) {
                best_fit = p;
            }
        }
    

        注意上面的逻辑, (p = p->child[p->child[0] != NULL]), PHP在尽量寻找最小的内存.

        为什么说, large_free_buckets是个键树呢, 从上面的逻辑我们可以看出, PHP把一个size, 按照二进制的01做键, 把内存大小信息反应到了键树上, 方便了快速查找.

        另外, 还有一个rest_buckets, 这个结构是个双向列表, 用来保存一些PHP分配后剩下的内存, 避免无意义的把剩余内存插入free_buckets带来的性能问题(此处, TIPI项目错误的描述为: “这是一个只有两个元素的数组。 而我们常用的插入和查找操作是针对第一个元素,即heap->rest_buckets[0]“).

    展开全文
  • Oracle-内存管理解读

    千次阅读 2016-11-11 00:47:27
    那Oracle 内存存储的主要内容是什么呢? 程序代码( PLSQL、 Java); 关于已经连接的会话的信息,包括当前所有活动和非活动会话; 程序运行时必须的相关信息,例如查询计划; Oracle 进程之间共享的信息和相互交流...

    概述

    这里写图片描述

    关于内存的配置,是最影响 Oracle性能的配置。内存还直接影响到其他两个重要资源的消耗: CPU 和 IO.

    那Oracle 内存存储的主要内容是什么呢?

    • 程序代码( PLSQL、 Java);
    • 关于已经连接的会话的信息,包括当前所有活动和非活动会话;
    • 程序运行时必须的相关信息,例如查询计划;
    • Oracle 进程之间共享的信息和相互交流的信息,例如锁;
    • 那些被永久存储在外围存储介质上,被 cache 在内存中的数据( 如 redo log 条目,数据块)。

    每个 Oracle 数据库都是由 Oracle Instance(实例)与数据库(数据文件,控制文件、重做日志文件)组成,其中所谓实例就是用户同数据库交互的媒介,用户通过于一个实例相连来操作数据库。

    而实例又是由统一的内存结构( SGA,PGA, UGA)和一批内存驻留进程组成。

    实例在操作系统中用 ORACLE_SID 来标识,在 Oracle 中用参数 INSTANCE_NAME 来标识, 它们两个的值是相同的。

    数据库启动时,系统首先在服务器内存中分配系统全局区( SGA), 构成了 Oracle的内存结构,然后启动若干个常驻内存的操作系统进程,即组成了 Oracle 的 进程结构,内存区域和后台进程合称为一个 Oracle 实例。


    SGA (System Gloable Area)

    架构图

    SGA概述

    SGA 是一组为系统分配的共享的内存结构,可以包含一个数据库实例的数据或控制信息。

    如果多个用户连接到同一个数据库实例,在实例的 SGA 中,数据可以被多个用户共享。

    当数据库实例启动时, SGA 的内存被自动分配;当数据库实例关闭时, SGA 内存被回收。

    SGA 是占用内存最大的一个区域,同时也是影响数据库性能的重要因素。

    SGA 区是可读写的。所有登录到实例的用户都能读取 SGA 中的信息,而在oracle 做执行操作时,服务进程会将修改的信息写入 SGA 区。

    SGA 主要包括了以下的数据结构:

    • 数据缓冲( Buffer Cache)
    • 重做日志缓冲( Redo Log Buffer)
    • 共享池( Shared Pool)
    • Java 池( Java Pool)
    • 大池( Large Pool)
    • 流池( Streams Pool — 10g 以后才有)
    • 数据字典缓存( Data Dictionary Cache)
    • 其他信息(如数据库和实例的状态信息)

    SGA 中的数据字典缓存其他信息 会被实例的后台进程所访问,它们在实例启动后就固定在 SGA 中了,而且不会改变,所以这部分又称为固定 SGA( Fixed SGA)。这部分区域的大小一般小于 100K。

    Shared Pool、 Java Pool、 Large Pool 和 Streams Pool 这几块内存区的大小是相应系统参数设置而改变的,所以有通称为可变 SGA( Variable SGA)。

    这里写图片描述


    SGA信息及含义

    使用有DBA权限的用户

    SQL> show parameter sga
    
    NAME                                 TYPE        VALUE
    ------------------- ----------- --------------------------
    lock_sga                             boolean     FALSE
    pre_page_sga                         boolean     FALSE
    sga_max_size                         big integer 6256M
    sga_target                           big integer 0

    或者查询v$parameter

    select a.name ,a.VALUE ,a.ISMODIFIED ,a.DESCRIPTION  from v$parameter a where a.NAME like '%sga%';

    这里写图片描述

    如果 ISSYS_MODIFIABLE 返回的是 false,说明该参数无法用 alter system语句动态修改,需要重启数据库。
    所以 sga_max_size 是不可以动态调整的。但是我们可以对sga_target 进行动态的调整。


    SGA_MAX_SIZE

    如果发现 SGA 各个内存总和大于 SGA_MAX_SIZE,它会将SGA_MAX_SIZE 的值修改为 SGA 各个内存区总和的值。

    SGA 所分配的是虚拟内存,但是,在我们配置 SGA 时,一定要使整个 SGA 区都在物理内存中,否则,会导致 SGA 频繁的页入/页出,会极大影响系统性能。

    对于 OLTP 系统, 一般的建议是将 SGA_MAX_SIZE 设为物理内存的 60%,PGA 设为 20%.

    下面给出一些参考值:

    这里写图片描述


    PRE_PAGE_SGA

    这个参数的默认值为FALSE,即不将全部SGA置入物理内存中。当设置为TRUE时,实例启动会将全部SGA置入物理内存中。

    它可以使实例启动达到它的最大性能状态,但是,启动时间也会更长(因为为了使所有SGA都置入物理内存中,oracle进程需要touch所有的SGA页)。

    SQL> alter system set pre_page_sga=true scope=spfile;

    LOCK_SGA

    为了保证SGA都被锁定在物理内存中,而不必页入/页出,可以通过参数LOCK_SGA来控制。

    这个参数默认值为FALSE,当指定为TRUE时,可以将全部SGA都锁定在物理内存中。

    当然,有些系统不支持内存锁定,这个参数也就无效了。


    SGA_TARGET

    Oracle10g中引入的一个非常重要的参数。

    在10g之前,SGA的各个内存区的大小都需要通过各自的参数指定,并且都无法超过参数指定大小的值,尽管他们之和可能并没有达到SGA的最大限制。此外,一旦分配后,各个区的内存只能给本区使用,相互之间是不能共享的。拿SGA中两个最重要的内存区Buffer Cache和Shared Pool来说,它们两个对实例的性能影响最大,但是就有这样的矛盾存在:在内存资源有限的情况下,某些时候数据被cache的需求非常大,为了提高buffer hit,就需要增加Buffer Cache,但由于SGA有限,只能从其他区“抢”过来——如缩小Shared Pool,增加Buffer Cache;而有时又有大块的PLSQL代码被解析驻入内存中,导致Shared Pool不足,甚至出现4031错误,又需要扩大Shared Pool,这时可能又需要人为干预,从Buffer Cache中将内存夺回来。

    10g 以后有了新特性:自动共享内存管理(Automatic Shared Memory Management ASMM)。

    而控制这一特性的,也就仅仅是这一个参数SGA_TARGE

    设置这个参数后,就不需要为每个内存区来指定大小了。SGA_TARGET指定了SGA可以使用的最大内存大小,而SGA中各个内存的大小由Oracle自行控制,不需要人为指定。Oracle可以随时调节各个区域的大小,使之达到系统性能最佳状态的个最合理大小,并且控制他们之和在SGA_TARGET指定的值之内。

    一旦给SGA_TARGET指定值后(默认为0,即没有启动ASMM),就自动启动了ASMM特性。如果不设置SGA_TARGET,则自动共享内存管理功能被禁止。

    设置了SGA_TARGET后,以下的SGA内存区就可以由ASMM来自动调整:

    • 共享池(Shared Pool)
    • Java池(Java Pool)
    • 大池(Large Pool)
    • 数据缓存区(Buffer Cache)
    • 流池(Streams Pool)

    对于SGA_TARGET的限制,它的大小是不能超过SGA_MAX_SIZE的大小的。

    要注意的是:当指定SGA_TARGET小于SGA_MAX_SIZE,实例重启后,SGA_MAX_SIZE就自动变为和SGA_TARGET一样的值了。

    在10g中,修改SGA_MAX_SIZE的值还是需要重启的.

    SGA_TARGET带来一个重要的好处就是,能使SGA的利用率达到最佳,从而节省内存成本。因为ASMM启动后,Oracle会自动根据需要调整各个区域的大小,大大减少了某些区域内存紧张,而某些区域又有内存空闲的矛盾情况出现。这也同时大大降低了出现4031错误的几率。


    SGA组成

    Database Buffer Cache

    Buffer Cache是SGA区中专门用于存放从数据文件中读取的的数据块拷贝的区域。Oracle进程如果发现需要访问的数据块已经在buffer cache中,就直接读写内存中的相应区域,而无需读取数据文件,从而大大提高性能.

    Buffer cache对于所有oracle进程都是共享的,即能被所有oracle进程访问。

    和Shared Pool一样,buffer cache被分为多个集合,这样能够大大降低多CPU系统中的争用问题。

    Buffer cache的管理

    Oracle对于buffer cache的管理,是通过两个重要的链表实现的:写链表最近最少使用链表(the Least Recently Used LRU).

    写链表所指向的是所有脏数据块缓存(即被进程修改过,但还没有被回写到数据文件中去的数据块,此时缓冲中的数据和数据文件中的数据不一致)。

    LRU链表指向的是所有空闲的缓存、pin住的缓存以及还没有来的及移入写链表的脏缓存。空闲缓存中没有任何有用的数据,随时可以使用。而pin住的缓存是当前正在被访问的缓存。LRU链表的两端就分别叫做最近使用端(the Most Recently Used MRU)和最近最少使用端(LRU)。


    Buffer cache的数据块访问

    当一个 Oracle 进程访问一个缓存时,这个进程会将这块缓存移到 LRU 链表中的 MRU。而当越来越多的缓冲块被移到 MRU 端,那些已经过时的脏缓冲(即数据改动已经被写入数据文件中,此时缓冲中的数据和数据文件中的数据已经一致)则被移到 LRU 链表中 LRU 端。

    当一个 Oracle 用户进程第一次访问一个数据块时,它会先查找 buffer cache中是否存在这个数据块的拷贝。如果发现这个数据块已经存在于 buffer cache(即命中 cache hit),它就直接读从内存中取该数据块。如果在 buffer cache 中没有发现该数据块(即未命中 cache miss),它就需要先从数据文件中读取该数据块到buffer cache 中,然后才访问该数据块。

    命中次数与进程读取次数之比就是我们一个衡量数据库性能的重要指标:buffer hit ratio(buffer命中率),可以通过以下语句获得自实例启动至今的buffer命中率.

    SQL> select (1-(sum(decode(name, 'physical reads',value,0))/(sum(decode(name, 'db block gets',value,0))
      2           +sum(decode(name,'consistent gets',value,0))))) * 100 "Hit Ratio"  from v$sysstat;
    
     Hit Ratio
    ----------
    99.6854209

    一个良好性能的系统,命中率一般保持在95%左右。


    Share Pool

    SGA中的共享池由库缓存(Library Cache)、字典缓存(Dictionary Cache)、用于并行执行消息的缓冲以及控制结构组成。

    Shared Pool的大小由参数SHARED_POOL_SIZE决定。10g 以后可以通过SGA_TARGET 参数来自动调整。

    对于Shared Pool的内存管理,是通过修正过的LRU算法表来实现的。

    库缓存(Library Cache)

    Library Cache中包括共享SQL区(Shared SQL Areas)、PL/SQL存储过程以及控制结构(如锁、库缓存句柄)。

    任何用户都可以访问共享SQL区(可以通过v$sqlarea访问)。因此库缓存存在于SGA的共享池中。

    共享SQL区和私有SQL区

    Oracle会为每一条SQL语句运行(每运行一条语句Oracle都会打开一个游标)提供一个共享SQL区(Shared SQL Areas)和私有SQL区(Private SQL Areas属于PGA)。当发现两个(或多个)用户都在运行同一SQL语句时,Oracle会重新组织SQL区,使这些用户能重用共享SQL区。但他们还会在私有SQL区中保存一份这条SQL语句的拷贝。

    一个共享SQL区中保存了一条语句的解析树和查询计划

    从解析语句到分配共享SQL区是一个比较消耗CPU的工程。这就是为什么我们提倡使用绑定变量的原因了。在没有使用绑定变量时,语句中的变量的数值不同,oracle就视为一条新的语句(9i后可以通过cursor_sharing来控制),重复上面的解析、内存分配的动作,将大大消耗系统资源,降低系统性能。

    PL/SQL程序单元

    Oracle对于PL/SQL程序单元(存储过程、函数、包、匿名PL/SQL块和触发器)的处理过程与SQL的处理方式类似。它会分配一个共享区来存储被解析、编译过的程序单元。


    字典缓存(Dictionary Cache)

    数据字典是有关于数据库的参考信息、数据库的结构信息和数据库中的用户信息的一组表和视图的集合,如我们常用到的V$视图、DBA_视图都属于数据字典。

    共享池的内存管理

    当一条SQL语句被提交给Oracle执行,Oracle会自动执行以下的内存分配步骤:

    1.Oracle检查共享池,看是否已经存在关于这条语句的共享SQL区。如果存在,这个共享SQL区就被用于执行这条语句。而如果不存在,Oracle就从共享池中分配一块新的共享SQL区给这条语句。同时,无论共享SQL区存在与否,Oracle都会为用户分配一块私有SQL区以保存这条语句相关信息(如变量值)。

    2. Oracle为会话分配一个私有SQL区。私有SQL区的所在与会话的连接方式相关。

    在以下情况下,Oracle也会将共享SQL区从共享池中释放出来:

    • 当使用ANALYZE语句更新或删除表、簇或索引的统计信息时,所有与被分析对象相关的共享SQL区都被从共享池中释放掉。当下一次被释放掉的语句被执行时,又重新在一个新的共享SQL区中根据被更新过的统计信息重新解析。

    • 当对象结构被修改过后,与该对象相关的所有共SQL区都被标识为无效(invalid)。在下一次运行语句时再重新解析语句。

    • 如果数据库的全局数据库名(Global Database Name)被修改了,共享池中的所有信息都会被清空掉。

    • DBA通过手工方式清空共享池:ALTER SYSTEM FLUSH SHARED_POOL;


    保留共享池

    通过视图V$SHARED_POOL_RESERVED可以查到保留池的统计信息。其中字段REQUEST_MISSES记录了没有立即从空闲列表中得到可用的大内存段请求次数。这个值要为0。

    因为保留区必须要有足够个空闲内存来适应那些短期的内存请求,而无需将那些需要长期cache住的没被pin住的可重建的段清除。否则就需要考虑增大SHARED_POOL_RESERVED_SIZE了。


    Shared Pool的重要参数

    $sgastat

    SHARED_POOL_SIZE
    SHARED_POOL_RESERVED_SIZE:指定了共享池中缓存大内存对象的保留区的大小
    _SHARED_POOL_RESERVED_MIN_ALLOC:设置了进入保留区的对象大小的阀值。


    Redo Log Buffer重做日志缓存

    Redo Log Buffer是SGA中一段保存数据库修改信息的缓存。

    .重做条目中包含了由于INSERT、UPDATE、DELETE、CREATE、ALTER或DROP所做的修改操作而需要对数据库重新组织或重做的必须信息。在必要时,重做条目还可以用于数据库恢复。

    参数LOG_BUFFER决定了Redo Log Buffer的大小。它的默认值是512K(一般这个大小都是足够的),最大可以到4G。10g中可通过参数自动设置。当系统中存在很多的大事务或者事务数量非常多时,可能会导致日志文件IO增加,降低性能。这时就可以考虑增加LOG_BUFFER。

    但是,Redo Log Buffer的实际大小并不是LOB_BUFFER的设定大小。为了保护Redo Log Buffer,oracle为它增加了保护页(一般为11K)

    SQL> show parameter log_buffer
    
    NAME                                 TYPE        VALUE
    ------------------------------------ ----------- ------------
    log_buffer                           integer     18317312
    
    
    SQL>  select * from v$sgastat where name = 'log_buffer';
    
    POOL   NAME                     BYTES
    ------------ -------------------------- ----------
                 log_buffer          18993152

    大池(large pool)

    大池是属于SGA的可变区(Variable Area)的,它不属于共享池。

    大池中只有两种内存段:空闲(free)和可空闲(freeable)内存段

    large pool是没有LRU链表的。

    Java池(Java Pool)

    Java池也是SGA中的一块可选内存区,它也属于SGA中的可变区。

    Java池的内存是用于存储所有会话中特定Java代码和JVM中数据。Java池的使用方式依赖与Oracle服务的运行模式。

    Java池的大小由参数JAVA_POOL_SIZE设置。Java Pool最大可到1G。

    在Oracle 10g以后,提供了一个新的建议器——Java池建议器——来辅助DBA调整Java池大小。建议器的统计数据可以通过视图V$JAVA_POOL_ADVICE来查询


    流池(Streams Pool)

    流池是Oracle 10g中新增加的。是为了增加对流的支持。

    流池也是可选内存区,属于SGA中的可变区。它的大小可以通过参数STREAMS_POOL_SIZE来指定。

    如果没有被指定,oracle会在第一次使用流时自动创建。如果设置了SGA_TARGET参数,Oracle会从SGA中分配内存给流池;

    如果没有指定SGA_TARGET,则从buffer cache中转换一部分内存过来给流池。转换的大小是共享池大小的10%。

    Oracle同样为流池提供了一个建议器——流池建议器。建议器的统计数据可以通过视图V$STREAMS_POOL_ADVICE查询。


    PGA(Program Global Area)

    PGA由两组区域组成:固定PGA和可变PGA

    它的内存段可以通过视图X$KSMPP(另外一个视图X$KSMSP可以查到可变SGA的内存段信息,他们的结构相同)查到。

    PGA堆包含用于存放X$表的的内存(依赖与参数设置,包括DB_FILES、CONTROL_FILES)。

    总的来说,PGA的可变区中主要分为以下三部分内容:

    • 1)私有SQL区;
    • 2)游标和SQL区
    • 3)会话内存

    UGA ( The User Global Area)

    UGA(User Global Area用户全局区)由用户会话数据、游标状态和索引区组成。

    PGA是服务于进程的,它包含的是进程的信息;而UGA是服务于会话的,它包含的是会话的信息


    CGA ( The Call Global Area)

    与其他的全局区不同,CGA(Call Global Area调用全局区)的存在是瞬间的。它只存在于一个调用过程中。对于实例的一些低层次的调用需要CGA,包括:
    1)解析一条SQL语句;
    2)执行一条SQL语句;
    3)取一条SELECT语句的输出值。

    Java调用内存也分配在CGA中。它被分为三部分空间:堆空间、新空间和老空间。


    软件代码区(Software Code Area)

    软件代码区是一部分用于存放那些正在运行和可以被运行的代码(Oracle自身的代码)的内存区。Oracle代码一般存储在一个不同于用户程序存储区的软件代码区,而用户程序存储区是排他的、受保护的区域。


    展开全文
  • 前言:这篇文章的主要内容由翻译而来,原文链接。但是大体内容与原文不尽相同,删除了一些内容,同时新增部分内容。由于本文大部分内容是翻译而来,若有理解不当之处还望谅解并指出,我会尽快进行修改。(内心:如果...
  • oracle内存管理

    2012-12-06 15:53:31
    先看Oracle内存存储的主要内容是什么: 程序代码(PLSQL、Java); 关于已经连接的会话的信息,包括当前所有活动和非活动会话; 程序运行时必须的相关信息,例如查询计划; Oracle进程之间共享的信息和相互交流...
  • JavaScript-内存管理

    万次阅读 2020-08-07 10:38:31
    本篇文章主要是介绍JavaScript内存管理的相关内容 随着近些年硬件技术的不断发展,同时高级编写语言当中也都自带了GC机制, 所以这样的一些变化就让我们在不需要特别注意内存空间使用的情况下也能够正常的完成相应...
  • PHP的内存管理, 分为俩大部分, 第一部分PHP自身的内存管理, 这部分主要的内容就是引用计数, 写时复制, 等等面向应用层面管理. 而第二部分就是今天我要介绍, zend_alloc中描写关于PHP自身的内存管理, 包括...
  • Object-c 内存管理

    2015-11-21 10:29:00
    1.内存管理的概念 2.引用计数 3.如何持有对象所有权 4.自动释放池 5.@property的使用 什么是内存管理 内存管理关于如何管理对象生命周期的编程原则。 int main(int argc, char *argv[]) { int value =...
  • PHP的内存管理, 分为俩大部分, 第一部分PHP自身的内存管理, 这部分主要的内容就是引用计数, 写时复制, 等等面向应用层面管理. 而第二部分就是今天我要介绍, zend_alloc中描写关于PHP自身的内存管理, 包括...
  • PHP的内存管理, 分为俩大部分, 第一部分PHP自身的内存管理, 这部分主要的内容就是引用计数, 写时复制, 等等面向应用层面管理. 而第二部分就是今天我要介绍, zend_alloc中描写关于PHP自身的内存管理, 包括...
  • PHP原理之内存管理

    2012-05-25 20:01:29
    PHP的内存管理, 分为俩大部分, 第一部分PHP自身的内存管理, 这部分主要的内容就是引用计数, 写时复制, 等等面向应用层面管理. 而第二部分就是今天我要介绍, zend_alloc中描写关于PHP自身的内存管理, 包括...
  • 但是这就涉及到一些内存管理的问题,如果放不下,是不是要放磁盘?什么时候认为放不下?这里会一一解读。 MemoryStore的putIterator 这个方法把一堆values的数组内容放入内存中(本质上就是放到Map<blockId, ...
  • 伙伴系统以页面为单位管理内存内存碎片也基于页面,即由大量离散且不连续页面组成。从内核角度,出现内存碎片不是什么事情,例如 有些情况下物理设备需要大量连续物理内存,如果内核无法满足,就...
  • 操作系统(内存管理)

    热门讨论 2009-09-20 12:55:25
    在很多脚本语言中,您不必担心内存如何管理的,这并不能使得内存管理的重要性有一点点降低。对实际编程来说,理解您的内存管理器的能力与局限性至关重要。在大部分系统语言中,比如 C 和 C++,您必须进行内存管理...
  • JVM 如何高效进行内存管理? 为什么需要有元空间,它又涉及什么问题? 带着这 3 个问题,我们开始今天学习,关于内存划分知识我希望在本课时你能够理解就可以,不需要死记硬背,因为在后面课时我们会经常...
  • 前面两篇文章介绍了Go语言的内存分配策略以及Go协程动态扩充和收缩栈内存的原理,今天这篇文章我们主要来聊一下内存管理的另外一大块内容:垃圾回收。下面首先我们会聊一下什么是GC,GC的作用是什么,然后再结合图示...
  • 记录一下,方便以后翻阅~ 主要内容: 1) 内存管理概述及原理; 2)相关实验代码解读。 官方资料:《STM32中文参考手册_V10》-第19章 灵活静态存储器控制器(FSMC)。...1.1 什么是内存管理 内存管理指软件运行
  • 使用Accessor方法的好处在于大大提高了类的封装性,使你可以简化一些基本的内存管理的内容 1.声明Accessor方法 声明相当简单,如果你稍微有点基础,就应该很熟悉下面举例的代码: @property (copy) NSString *...
  • 日期 内核版本 CPU架构 作者 2019.04.06 Linux-4.4 PowerPC ...在介绍系统启动阶段的内容之前先来了解一些基本知识,方便我们理解相应准备和操作原理是什么主要有五点...
  • 前面两篇文章介绍了Go语言的内存分配策略以及Go协程动态扩充和收缩栈内存的原理,今天这篇文章我们主要来聊一下内存管理的另外一大块内容:垃圾回收。下面首先我们会聊一下什么是GC,GC的作用是什么,然后再结合图示...
  • 这就是内存管理要解释的内容。     内存管理主要涉及两个方面:   从逻辑地址到线性地址转变 从线性地址到物理地址转变(分页)   所谓逻辑地址,其实就是在段中偏移地址。比如...
  • 主要的核心就是:CPU管理、内存管理、磁盘管理、文件管理(硬盘管理),还有一个隐藏进程管理 2)操作系统中库函数和系统调用 1>概念:为什么要有库函数和系统调用函数,主要是为了保护操作系统。将内存分为...
  •  内存碎片是内存管理中非常重要又非常棘手问题,就算强大Linux也没有办法完全解决,但好在经过多年发展,Linux已经有一套相当成熟反碎片技术,包括:针对页外碎片伙伴系统和针对页内碎片slab分配技术。...
  • 转:... 第六讲:Obj-C 内存管理4 - 自动释放池 主要内容 什么是自动释放池 自动释放池好处 如何创建一个自动释放池 自动释放池如何释放对象内存 自动释...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 724
精华内容 289
关键字:

内存管理的主要内容是什么