精华内容
下载资源
问答
  • python中的内存管理和垃圾回收机制(附gc(Garbage Collection)模块常用方法) python是一种动态的脚本语言,因此它的一些特性和cpp语言等有所不同。python是通过对象和引用来将实际的储存区域中的内容和变量建立...

    python中的内存管理和垃圾回收机制(附gc(Garbage Collection)模块常用方法)

    python是一种动态的脚本语言,因此它的一些特性和cpp语言等有所不同。python是通过对象引用来将实际的储存区域中的内容和变量建立联系的。在python中的内存管理和垃圾回收主要有以下几个需要了解的地方:减小频繁申请和释放内存带来的不便利所引入的内存池机制,以及垃圾回收的标记-清除和分代回收机制。下面简单介绍。

    python的内存管理

        _____   ______   ______       ________
       [ int ] [ dict ] [ list ] ... [ string ]       Python core         |
    +3 | <----- Object-specific memory -----> | <-- Non-object memory --> |
        _______________________________       |                           |
       [   Python's object allocator   ]      |                           |
    +2 | ####### Object memory ####### | <------ Internal buffers ------> |
        ______________________________________________________________    |
       [          Python's raw memory allocator (PyMem_ API)          ]   |
    +1 | <----- Python memory (under PyMem manager's control) ------> |   |
        __________________________________________________________________
       [    Underlying general-purpose allocator (ex: C library malloc)   ]
     0 | <------ Virtual memory allocated for the python process -------> |
    
       =========================================================================
        _______________________________________________________________________
       [                OS-specific Virtual Memory Manager (VMM)               ]
    -1 | <--- Kernel dynamic storage allocation & management (page-based) ---> |
        __________________________________   __________________________________
       [                                  ] [                                  ]
    -2 | <-- Physical memory: ROM/RAM --> | | <-- Secondary storage (swap) --> |
    

    可以看出,python的内存管理主要分为四个层次结构,直接面向用户的是标记为+3的一层,它提供给我们int,list,string,dict等方法;第0层是操作系统的内存管理借口,python无法干涉;第1层是python管理维护,为了适应不同的系统可移植性的需要建立的,是对第0层的进一步封装;第2层也是python管理维护,负责对象的建立和销毁,包含参数和引用计数等。

    python的内存池机制

    为了便于较小的对象的管理和使用,python中引入了所谓的内存池机制,对于小于256Byte的,直接通过内存池分配,内存池也有其结构,最小的单元为Block,大小为8的整数倍。对于像整数之类的不可变对象,还有对象缓冲池。比如:

    a = 1
    b = 3
    c = 1
    hex(id(a))
    Out[5]: '0x23c2168'
    hex(id(b))
    Out[6]: '0x23c2138'
    hex(id(c))
    Out[7]: '0x23c2168'

    可以看出,虽然a和c不是用a = c赋值的,但是实际上他们还是指向同一个位置。说明在python中,1这个不可变的常数对象是有固定的位置的,而所有赋值为1的变量都是它的引用。短字符串也是这样的:

    a = 'haha'
    b = 'hahaha'
    c = 'haha'
    hex(id(a))
    Out[11]: '0x7fc94388bab0'
    hex(id(b))
    Out[12]: '0x7fc94388b870'
    hex(id(c))
    Out[13]: '0x7fc94388bab0'

    python的垃圾回收策略:标记-清除 和 分代回收

    由于python是对象和引用构成的,因此我们不需要预先声明变量类型和开辟空间就可以直接将某个变量赋值。这个赋值的过程实际上就是把某个引用指向某个既定的对象的过程。就好比给一个物品上贴上标签。比如:

    ref1 = [1,2,3,4]
    ref2 = [3,4,5]
    ref3 = ref1
    ref3
    Out[22]: [1, 2, 3, 4]
    hex(id(ref3)) == hex(id(ref1))
    Out[23]: True
    ref3[1] = 4
    ref3
    Out[25]: [1, 4, 3, 4]
    ref1
    Out[26]: [1, 4, 3, 4]
    ref3 = 6
    ref3
    Out[28]: 6
    ref1
    Out[29]: [1, 4, 3, 4]

    可以看出,直接赋值只是给已经存在的对象再贴上一个标签而已,因为两者指向的是同一个对象,所以修改一个会影响其他的。

    可以使得引用增加的操作:

    • 对象被创建,a = 1
    • 对象被引用,b = a
    • 对象被作为参数传入 fun(a)
    • 对象被作为容器元素 c = [a,a,a]

    可以使得引用减少的操作:

    • 对象被显式销毁,del a
    • 对象的引用指向了新的对象,如本来a = b,然后a = c,那么b的引用就少一个
    • 对象所在的容器被销毁
    • 局部变量离开作用域

    由这种模式下,何时进行废弃对象的回收呢?一个很直接的思路就是,如果没有标签贴在某个实体上,也就是说,一个对象的引用数为零的时候,就要对它进行回收。这个就是标记清除的基本思路,也可以叫 引用计数 的策略。但是对于一种特殊情形,即循环引用的情况,这种等到引用数为零在回收的想法就遇到了困难,比如我们建立两个对象A和B,其中A.next = B,而B.pre = A,这在python中是可行的,因为允许class的属性在使用中加入。这样以来,AB都有至少一个来自对方的引用,然而可能两个都没有外部引用,也就是不使用了,但是直接查找的话也无法销毁这两个对象。

    如果每一次有新的操作都进行一次检查看看是否有需要回收的话,就比较费时费力,因此我们的检查应该不能过于频繁,而且又要保证及时的回收。python中应用了分代回收机制 。简单来说就是,将存在时间短的对象容易死掉,而老年的对象不太容易死,这叫做弱代假说(weak generation hypothesis),这也很好理解,一般生命周期长的对象往往是全局变量,而短的多为局部变量或者临时定义的变量。那么,我们把当前的对象作为第0代,我们每当allocation比deallocation多到某个阈值时,就对这些对象做一次检查和清理,没有被清理的那些就存活下来,进入第1代,第一代检查做若干次后,对1代清理,存活下来的进入第2代,第二代也是如此。这样就实现了分代回收的操作。

    gc 模块的简要说明及其主要方法

    gc模块的回收就是用分代回收的策略来解决循环引用的不可回收的问题,下面是gc模块的常见的方法及其说明:

    gc.enable()

    Enable automatic garbage collection.
    

    gc.disable()

    Disable automatic garbage collection.
    

    gc.isenabled()

    Returns true if automatic collection is enabled.
    

    gc.collect(generation=2)

    With no arguments, run a full collection. The optional argument generation may be an integer specifying which generation to collect (from 0 to 2). A ValueError is raised if the generation number is invalid. The number of unreachable objects found is returned.
    
    The free lists maintained for a number of built-in types are cleared whenever a full collection or collection of the highest generation (2) is run. Not all items in some free lists may be freed due to the particular implementation, in particular float.
    

    gc.set_debug(flags)

    Set the garbage collection debugging flags. Debugging information will be written to sys.stderr. See below for a list of debugging flags which can be combined using bit operations to control debugging.
    

    gc.get_debug()

    Return the debugging flags currently set.
    

    gc.get_objects()

    Returns a list of all objects tracked by the collector, excluding the list returned.
    

    gc.get_stats()

    Return a list of three per-generation dictionaries containing collection statistics since interpreter start. The number of keys may change in the future, but currently each dictionary will contain the following items:
    
        collections is the number of times this generation was collected;
        collected is the total number of objects collected inside this generation;
        uncollectable is the total number of objects which were found to be uncollectable (and were therefore moved to the garbage list) inside this generation.
    
    New in version 3.4.
    

    gc.set_threshold(threshold0[, threshold1[, threshold2]])

    Set the garbage collection thresholds (the collection frequency). Setting threshold0 to zero disables collection.
    
    The GC classifies objects into three generations depending on how many collection sweeps they have survived. New objects are placed in the youngest generation (generation 0). If an object survives a collection it is moved into the next older generation. Since generation 2 is the oldest generation, objects in that generation remain there after a collection. In order to decide when to run, the collector keeps track of the number object allocations and deallocations since the last collection. When the number of allocations minus the number of deallocations exceeds threshold0, collection starts. Initially only generation 0 is examined. If generation 0 has been examined more than threshold1 times since generation 1 has been examined, then generation 1 is examined as well. Similarly, threshold2 controls the number of collections of generation 1 before collecting generation 2.
    

    gc.get_count()

    Return the current collection counts as a tuple of (count0, count1, count2).
    

    gc.get_threshold()

    Return the current collection thresholds as a tuple of (threshold0, threshold1, threshold2).
    

    下面这些是gc.debug的flag的说明:

    gc.DEBUG_STATS

    Print statistics during collection. This information can be useful when tuning the collection frequency.
    

    gc.DEBUG_COLLECTABLE

    Print information on collectable objects found.
    

    gc.DEBUG_UNCOLLECTABLE

    Print information of uncollectable objects found (objects which are not reachable but cannot be freed by the collector). These objects will be added to the garbage list.
    
    Changed in version 3.2: Also print the contents of the garbage list at interpreter shutdown, if it isn’t empty.
    

    gc.DEBUG_SAVEALL

    When set, all unreachable objects found will be appended to garbage rather than being freed. This can be useful for debugging a leaking program.
    

    gc.DEBUG_LEAK

    The debugging flags necessary for the collector to print information about a leaking program (equal to DEBUG_COLLECTABLE | DEBUG_UNCOLLECTABLE | DEBUG_SAVEALL).
    

    gc的垃圾回收在程序结束、达到阈值,以及显式调用gc.collect()时启动。

    2018年04月13日00:11:42

    展开全文
  • Windows内存管理的方法

    2019-10-03 10:10:53
    内存管理是操作系统中的重要部分,两三句话恐怕谁也说不清楚吧~~我先说个大概,希望...把哪些不常用的程序片断就放入虚拟内存,当需要用到它的时候在load入主存(物理内存)中。这个就是内存管理所要做的事。内存...

    内存管理是操作系统中的重要部分,两三句话恐怕谁也说不清楚吧~~
    我先说个大概,希望能够抛砖引玉吧

    当程序运行时需要从内存中读出这段程序的代码。代码的位置必须在物理内存中才能被运行,由于现在的操作系统中有非常多的程序运行着,内存中不能够完全放下,所以引出了虚拟内存的概念。把哪些不常用的程序片断就放入虚拟内存,当需要用到它的时候在load入主存(物理内存)中。这个就是内存管理所要做的事。内存管理还有另外一件事需要做:计算程序片段在主存中的物理位置,以便CPU调度。

    内存管理有块式管理,页式管理,段式和段页式管理。现在常用段页式管理

    块式管理:把主存分为一大块、一大块的,当所需的程序片断不在主存时就分配一块主存空间,把程 序片断load入主存,就算所需的程序片度只有几个字节也只能把这一块分配给它。这样会造成很大的浪费,平均浪费了50%的内存空间,但时易于管理。

    页式管理:把主存分为一页一页的,每一页的空间要比一块一块的空间小很多,显然这种方法的空间利用率要比块式管理高很多。

    段式管理:把主存分为一段一段的,每一段的空间又要比一页一页的空间小很多,这种方法在空间利用率上又比页式管理高很多,但是也有另外一个缺点。一个程序片断可能会被分为几十段,这样很多时间就会被浪费在计算每一段的物理地址上(计算机最耗时间的大家都知道是I/O吧)。

    段页式管理:结合了段式管理和页式管理的优点。把主存分为若干页,每一页又分为若干段。好处就很明显,不用我多说了吧。

    各种内存管理都有它自己的方法来计算出程序片断在主存中的物理地址,其实都很相似。

    这只是一个大概而已,不足以说明内存管理的皮毛。无论哪一本操作系统书上都有详细的讲解

    转载于:https://www.cnblogs.com/omygod/archive/2006/11/15/560762.html

    展开全文
  • Java虚拟机在执行Java程序的过程中会把它管理的内存划分成若干个不同的数据区域。JDK. 1.8和之前的版本略不同,下面会介绍到。 JDK1.8之前 JDK1.8 线程私有的 / 共享 线程私有的 程序计数器 虚拟机栈 本地方法...

    运行时数据区域

    Java虚拟机在执行Java程序的过程中会把它管理的内存划分成若干个不同的数据区域。JDK1.8和之前的版本略有不同,下面会介绍到。

    JDK1.8之前

    在这里插入图片描述

    JDK1.8

    在这里插入图片描述

    线程私有的 / 共享

    线程私有的

    • 程序计数器
    • 虚拟机栈
    • 本地方法栈

    线程共享的

    • 方法区
    • 直接内存(非运行时数据区的一部分)

    程序计数器

    程序计数器是一块较小的内存空间, 可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等功能都需要依赖这个计数器来完成。

    另外,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。

    从上面的介绍中我们知道程序计数器主要有两个作用

    • 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。
    • 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。

    注意:程序计数器是唯一个不会出现 OutOfMemoryError的内存区域,它的生命周期随着线程的创建而创建,随着线程的结束而死亡。

    Java虚拟机栈

    与程序计数器一样,Java 虚拟机栈也是线程私有的,它的生命周期和线程相同,描述的是Java方法执行的内存模型,每次方法调用的数据都是通过栈传递的。 Java内存可以粗糙的区分为堆内存(Heap) 和栈内存(Stack),其中栈就是现在说的虚拟机栈,或者说是虚拟机栈中局部变量表部分。(实际上,Java 虚拟机栈是由一个个栈帧组成,而每个栈帧中都拥有:局部变童表、操作数栈、动态链接、方法出口信息。)

    局部变量表主要存放了编译器可知的各种数据类型(boolean、 byte、 char、short、int、float、 long、 double)
    对象引用 (reference 类型,它不同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)。

    Java虚拟机栈会出现两种错误: StackOverFlowError 和OutOfMemoryError。

    • StackOverFlowError:若Java虚拟机栈的内存大小怀允许动态扩展,那么当线程请求栈的深度超过当前Java虚拟机栈的最大深度的时候,就抛出StackOverFlowError错误。
    • OutOfMemoryError:若Java虚拟机栈的内存大小允许动态扩展,且当线程请求栈时内存用完了,无法再动态扩展了,此时抛出OutOfMemoryError错误。

    Java虚拟机栈也是线程私有的,每个线程都有各自的Java虚拟机栈,而且随着线程的创建而创建,随着线程的死亡而死亡。

    那么方法/函数如何调用?
    Java栈可以类比数据结构中的栈,Java 栈中保存的主要内容是栈帧,每一次函数调用都会有一个对应的栈帧被压入Java栈,每个函数调用结束后,都会有一个栈帧被弹出。

    Java方法有两种返回方式:

    • return语句
    • 抛出异常

    不管哪种返回方式都会导致栈帧被弹出。

    本地方法栈

    和虚拟机栈所发挥的作用非常相似,区别是:虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。 在HotSpot虚拟机中和Java虚拟机栈合二为一。

    本地方法被执行的时候,在本地方法栈也会创建一个栈帧, 用于存放该本地方法的局部变量表、操作数栈、动态链接、出口信息。
    方法执行完毕后相应的栈帧也会出栈并释放内存空间,也会出现StackOverFlowError和OutOfMemoryError两种错误。

    Java虚拟机所管理的内存中最大的一块,Java堆是所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例以及数组都在这里分配内存。

    Java堆是垃圾收集器管理的主要区域,因此也被称作GC堆(Garbage CollectedHeap)。从垃圾回收的角度,由于现在收集器基本都采用分代垃圾收集算法,所以Java堆还可以细分为:新生代和老年代:再细致一点有: Eden 空间、FromSurvivor、To Survivor空间等。进一步划分的目的是更好地回收内存,或者更快地分配内存。
    在JDK7版本及JDK7版本之前,堆内存被通常被分为下面三部分:

    • 新生代内存(Young Generation)
    • 老生代(Old Generation)
    • 永生代(Permanent Generation)

    下图所示的Eden区、两个Survivor区都属于新生代(为了区分,这两个Survivor区域按照顺序被命名为from和to),中间一层属于老年代。
    在这里插入图片描述
    JDK 8版本之后方法区(HotSpot 的永久代)被彻底移除了(JDK1.7 就已经开始了)取而代之是元空间,元空间使用的是直接内存。
    在这里插入图片描述

    大部分情况,对象都会首先在Eden区域分配,在一次新生代垃圾回收后, 如果对象还存活,则会进入S0或者S1,并且对象的年龄还会加1(Eden区->Survivor区后对象的初始年龄变为1),当它的年龄增加到一定程度(默认为15岁),就会被晋升到老年代中。对象晋升到老年代的年龄阈值,可以通过参数-XX:Max TenuringThreshold来设置。

    “Hotspot遍历所有对象时,按照年龄从小到大对其所占用的大小进行累积,当累积的某个年龄大小超过了survivor区的一半时,取这个年龄和Max TenuringThreshold中更小的一个值,作为新的晋升年龄阈值”。

    动态年龄计算的代码如下

    uint ageTable: :compute_ tenuring_ threshold(size_ t
    survivor_ capacity){
    //survivor_ capacity是survivor空间的大小
      size_ t desired_ survivor_ size =(size_ t)((( (double)
    survivor_ capacity)*TargetSurvivorRatio)/100);
      size_ t total =0
      uint age =1;
      while(age < table_ size){
         total += sizes[age];//sizes数组是 每个年龄段对象大小
         if(total > desired_ survivor_ size)break;
         age++;
     }
       uint result = age < MaxTenuringThreshold ? age :
    MaxTenuringThreshold;
    ....
    }
    

    堆这里最容易出现的就是OutOfMemoryError错误,并且出现这种错误之后的表现形式还会有几种,比如:

    • OutOfMemoryError: GC Overhead Limit Exceeded:当JVM花太多时间执行垃圾回收并且只能回收很少的堆空间时,就会发生此错误。
    • java.lang. OutOfMemoryError: Java heap space :假如在创建新的对象时,堆内存中的空间不足以存放新创建的对象,就会引发。
    • java.lang.OutOfMemoryError:Java heap space错误。(和本机物理内存无关,和你配置的内存大小有关! )

    方法区

    方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap (非堆),目的应该是与Java堆区分开来。

    方法区也被称为永久代。

    方法区和永久代的关系

    《Java虚拟机规范》只是规定了有方法区这么个概念和它的作用,并没有规定如何去实现它。那么,在不同的JVM上方法区的实现肯定是不同的了。方法区和永久代的关系很像Java中接口和类的关系,类实现了接口,而永久代就是HotSpot虚拟机对虚拟机规范中方法区的一种实现方式。 也就是说,永久代是HotSpot的概念,方法区是Java虚拟机规范中的定义,是一种规范,而永久代是一种实现,一个是标准一个是实现, 其他的虚拟机实现并没有永久代这一说法。、

    常用参数

    JDK 1.8之前永久代还没被彻底移除的时候通常通过下面这些参数来调节方法区大小

    • – XX:PermSize=N//方法区 (永久代)初始大小
    • – XX:MaxPermSize=N//方法区 (永久代)最大大小,超过这个值将会抛出OutOfMemoryError

    相对而言,垃圾收集行为在这个区域是比较少出现的,但并非数据进入方法区后就“永久存在"了。

    JDK 1.8的时候,方法区(HotSpot 的永久代)被彻底移除了(JDK1.7 就已经开始了),取而代之是元空间,元空间使用的是直接内存。
    下面是一些常用参数:

    • – XX:MetaspaceSize=N//设置 Metaspace(元空间)的初始(和最小大小)
    • — XX:MaxMetaspaceSize=N//设置Metaspace(元空间)的最大大小

    与永久代很大的不同就是,如果不指定大小的话,随着更多类的创建,虚拟机会耗尽所有可用的系统内存。

    为什么要将永久代(PermGen)替换为元空间(MetaSpace)呢?

    整个永久代有一个JVM本身设置固定大小上限,无法进行调整,而元空间使用的是直接内存,受本机可用内存的限制,虽然元空间仍旧可能溢出,但是比原来出现的几率会更小。
    当你元空间溢出时会得到如下错误: java. lang OutOfMemoryError : MetaSpace
    你可以使用-XX: MaxMetaspaceSize 标志设置最大元空间大小,默认值为unlimited,这意味着它只受系统内存的限制。
    -XX: MetaspaceSize 调整标志定义元空间的初始大小如果未指定此标志,则Metaspace将根据运行时的应用程序需求动态地重新调整大小。
    元空间里面存放的是类的元数据,这样加载多少类的元数据就不由MaxPermSize控制了,而由系统的实际可用空间来控制,这样能加载的类就更
    多了。
    在JDK8,合并HotSpot和JRockit的代码时,JRockit从来没有一个叫永久代的东西,台并之后就没有必要额外的设置这么一个永久代的地方了。

    运行时常量池

    运行时常量池是方法区的一部分。Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有常量池信息(用于存放编译期生成的各种字面量和符号引用)
    既然运行时常量池是方法区的一部分,自然受到方法区内存的限制,当常量池无法再申请到内存时会抛出OutOfMemoryError错误。
    JDK1.7及之后版本的JVM已经将运行时常量池从方法区中移了出来,在Java堆(Heap)中开辟了一块区域存放运行时常量池。
    在这里插入图片描述

    直接内存

    直接内存并不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用。而且也可能导致OutOfMemoryError错误出现。

    JDK1.4中新加入的NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓存区(Buffer) 的I/O方式,它可以直接使用Native函数库直
    接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这样就能在一些场景中显著提高性能,因为避免了在Java堆和Native堆之间来回复制数据。本机直接内存的分配不会受到Java堆的限制,但是,既然是内存就会受到本机总内存大小以及处理器寻址空间的限制。

    补充(Native关键字)

    在这里插入图片描述凡是带了native关键字的,说明Java的作用范围已经达不到了,会去调用底层的C语言库,会进入本地方法栈,调用本地方法接口(JNI);

    本地方法接口(JNI)作用:扩展Java的使用,融合不同的语言为Java所用

    内存中专门开辟了一个标记区域:Native Method Stack,登记native 方法 ,会在最终执行的时候,通过本地方法接口(JNI)加载本地方法

    在这里插入图片描述

    展开全文
  • //联系人:石虎 QQ:1224614774 昵称:嗡嘛呢叭咪哄 ... 当程序运行时需要从内存中读出这段程序代码。代码位置必须在物理内存中才能被运行,由于现在操作系统中非常多程序运行...这个就是内存管理所要

    //联系人:石虎 QQ:1224614774 昵称:嗡嘛呢叭咪哄


    一、虚拟内存的概念

       当程序运行时需要从内存中读出这段程序的代码。代码的位置必须在物理内存中才能被运行,由于现在的操作系统中有非常多的程序运行着,内存中不能够完全放下,所以引出了虚拟内存的概念。把哪些不常用的程序片断就放入虚拟内存,当需要用到它的时候在load入主存(物理内存)中。这个就是内存管理所要做的事。内存管理还有另外一件事需要做:计算程序片段在主存中的物理位置,以便CPU调度。



    二、内存管理


    1.内存管理有块式管理,页式管理,段式和段页式管理。现在常用段页式管理


      块式管理:把主存分为一大块、一大块的,当所需的程序片断不在主存时就分配一块主存空间,把程 序片断load入主存,就算所需的程序片度只有几个字节也只能把这一块分配给它。这样会造成很大的浪费,平均浪费了50%的内存空间,但时易于管理。


      页式管理:把主存分为一页一页的,每一页的空间要比一块一块的空间小很多,显然这种方法的空间利用率要比块式管理高很多。


      段式管理:把主存分为一段一段的,每一段的空间又要比一页一页的空间小很多,这种方法在空间利用率上又比页式管理高很多,但是也有另外一个缺点。一个程序片断可能会被分为几十段,这样很多时间就会被浪费在计算每一段的物理地址上(计算机最耗时间的大家都知道是I/O吧)。


      段页式管理:结合了段式管理和页式管理的优点。把主存分为若干页,每一页又分为若干段。好处就很明显,不用我多说了吧。

    各种内存管理都有它自己的方法来计算出程序片断在主存中的物理地址,其实都很相似。


    三、指针和引用的区别,引用可以用常指针实现?

      1.本质上的区别是,指针是一个新的变量,只是这个变量存储的是另一个变量的地址,我们通过访问这个地址来修改变量。

    而引用只是一个别名,还是变量本身。对引用进行的任何操作就是对变量本身进行操作,因此以达到修改变量的目的。


     (1)指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元;而引用跟原来的变量实质上是同一个东西,只不过是原变量的一个别名而已。如:

        int a=1;int *p=&a;

        int a=1;int &b=a;

        上面定义了一个整形变量和一个指针变量p,该指针变量指向a的存储单元,即p的值是a存储单元的地址。

        而下面2句定义了一个整形变量a和这个整形a的引用b,事实上a和b是同一个东西,在内存占有同一个存储单元。

     (2)可以有const指针,但是没有const引用;

     (3)指针可以有多级,但是引用只能是一级(int **p;合法 而int &&a是不合法的)

     (4)指针的值可以为空,但是引用的值不能为NULL,并且引用在定义的时候必须初始化;

     (5)指针的值在初始化后可以改变,即指向其它的存储单元,而引用在进行初始化后就不会再改变了。

     (6)"sizeof引用"得到的是所指向的变量(对象)的大小,而"sizeof指针"得到的是指针本身的大小;

     (7)指针和引用的自增(++)运算意义不一样;


    注意: 指针传参的时候,还是值传递,试图修改传进来的指针的值是不可以的。只能修改地址所保存变量的值。

    引用传参的时候,传进来的就是变量本身,因此可以被修改。


    谢谢!!!

    展开全文
  • 在做Java开发的时候常用的JVM内存管理有两种,一种是堆内存,一种是栈内存。堆内存主要用来存储程序在运行时创建或实例化的对象与变量,例如:我们通过new MyClass()创建的类MyClass的对象。而栈内存则是用来存储...
  • 如果crash地方内存明显不是consistent,或者内存管理信息都已被破坏,并且还是随机出现,那就比较麻烦了。当然,祼看code打log是一个办法,但其效率不是太高,尤其是在运行成本高或重现概率低情况下。另外,...
  • 或者如果你使用@synthesize关键字,也是读取器方法被解析。而且如果你试图使用点操作符为属性赋值,你将得到一个编译错误。 readwrite此标记说明属性会被当成读写,这也是默认属性。设置器和读取器都需要在@...
  • Linux中的常用内存问题检测工具

    万次阅读 多人点赞 2015-06-27 12:53:08
    如果crash地方内存明显不是consistent,或者内存管理信息都已被破坏,并且还是随机出现,那就比较麻烦了。当然,祼看code打log是一个办法,但其效率不是太高,尤其是在运行成本高或重现概率低情况下。另外,...
  • PID,PID控制模块 PID2组:PID1,PID2 属性: PID#_output 方法: reset_PID(PID#) ;RESET All variable to zero ...NVM是非易失的内存模块,40组。NVM1~NVM40.每一个里面15个元素+checksum。 需...
  • 本文为详解JVM的内存管理机制,从JVM的垃圾回收机制和JVM中对象的生命周期、析构方法finalize、静态变量和内存管理许多技巧和方式等方面为大家介绍JVM的内存管理机制。 AD: 我们在深入Java核心...
  • ARC:Xcode新默认编译器Apple LLVM,代替了以前LLVM-GCC ,使用了Clang作为前端,Clang带一个静态分析器,在代码编译前会进行分析,在需要加入retain和release地方由分析器代劳进行补全。 ARC可以代劳大量...
  • Magnifier(开发中暂未落地) 执行方法 50%内存阀值监控 查看法 级别必须执行 使用这个步骤基本上就能帮助测试发现和监控50%进程内存阀值红线触及情况 方法 使用DDMS设备进程管理器只有调试版apk所
  • 内容包括(应用优化、查询缓存优化、内存管理优化、并发参数调整、锁问题、SQL技巧) 应用优化方法 1 使用连接池 对于访问数据库来说,建立连接代价是比较昂贵,因为我们频繁创建关闭连接,是比较耗费资源,...
  • 动态内存管理

    2020-03-04 20:39:35
    我们常用的内存开辟的方法有: int arr[10] = {0}; //在栈上开辟40个字节的连续空间 int ret = 0; //在栈上开辟4个字节的空间 但是上述的开辟空间的方式有两个特点: 空间开辟大小是固定的。 数组在申明的时候,...
  • 忘记密码是很常见事情。有些用户将密码保存在其默认浏览器内存中,几个月后您可能会忘记任何事情。...本文介绍了如何重置Joomla管理员密码。通常,您可以从后端用户管理...几种方法可以恢复Joomla管理员密码。基本...
  • 在电脑当中,内存有着相当重要作用,因为电脑当中所有运行程序都是在内存中... 一、卸载不常用程序和关闭启动项 通过任务管理器,我们可以了解当前所使用内存的详细信息,并且卸载那些不常用且占用大量系统...
  • 内存管理2

    2019-09-24 17:18:36
    在虚拟存储方案中 常用的页面调入策略两种请求调页和预调页 移动技术可以解决外部碎片不能解决内部碎片 页面置换策略中先进先出页面置换算法(FIFO)总是选择最先换入的页面调出 最近不常用页面置换算法(LFU)...
  • 目的是使学生掌握常用操作系统(如DOS、Windows或Linux)一般管理方法,了解它是如何组织和运作,对操作系统核心概念和算法一个透彻理解,并对系统运行机制一个全面掌握,从而充分理解系统调...
  • 内存管理有块式管理,页式管理,段式和段页式管理。现在常用段页式管理。 块式管理:把主存分为一大块、一大块,当所需程序片断不在主存时就分配一块主存空间,把程序片断load入主存,就算所需程序片度只有几...
  • 所以,如果想对内存映射文件更深刻的认识,必须对Windows操作系统的内存管理机制清楚的认识,内存管理的相关知识非常复杂,超出了本文的讨论范畴,在此就不再赘述,感兴趣的读者可以参阅其他相关书籍。...
  • JVM管理内存

    2011-08-28 00:01:12
    JVM管理内存的方式: 堆内存Heap:对象实例与变量 栈内存Stack:静态方法   对象引用结构层次: ...2. 软引用:较强引用功能,只有内存不够时候才回收这类内存,实现一些常用资源cache功能。软引
  • 内存数据库抛弃了磁盘数据管理的传统方式,基于全部数据都在内存中重新设计了体系结构,并且在数据缓存、快速算法、并行操作方面也进行了相应改进,所以数据处理速度比传统数据库数据处理速度要快很多。...
  • 内存分配内存内存池是一种常用的代替系统内存分配的方法优点:速度远比malloc/free快,因为减少了系统调用的次数,特别是频繁申请/释放内存块的情况避免了频繁申请/释放内存之后,系统的大量内存碎片可避免内存...
  • SDWebImage 常用方法

    2015-11-30 13:25:00
    SDWebImage是iOS中一款处理图片框架,...SDWebImage会自动去管理这些图片, 包括缓存到内存和缓存到磁盘等等。包括gif图片显示也是轻松完成。本文主要分享除了基本方法以外一些其他给力方法。 图片下载 图片下...

空空如也

空空如也

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

常用的内存管理方法有