精华内容
下载资源
问答
  • 操作系统:LRU置换算法实现
    千次阅读
    2020-12-17 20:20:21
    1. 最近最久未使用(LRU)置换算法原理 就是:当需要淘汰某页面时,选择当前一段时间内最久未使用过的页先淘汰, 即淘汰距当前最远的上次使用的页。
      例如: 分配给该进程的页块数为3,一个20长的页面访问序列为 :12560,36536,56042,70435, 则缺页次数和缺页率按下图给出:

    2. 假定分配给该进程的页块数为3,页面访问序 列长度为20。本实验可以采用数组结构实现, 首先随机产生页面序列,当发生请求调页时, 若内存已满,则需要利用LRU算法,将当前一段时间内最久未使用过的页替换出去。

    数据结构:
    struct memory //表示每一个页块
    {
    int num;
    int time;
    }page[100];
    void print()//打印
    int find() //找到最久未置换或者空页块
    void run() //时间加1
    void change(memory page[],int xulie[]) //页块分配

    具体代码:

    #include <iostream>
    #include <stdlib.h>
    using namespace std;
    struct memory
    {
    	int num;
    	int time;
    }page[100];
    
    int count=0;
    int n, m;
    
    void print()//打印 
    {
    	cout<<"页块号     内容     时间"<<endl;
    	for(int i=0;i<n;i++)
    	{
    		cout<<i+1<<"         "<<page[i].num<<"          "<<page[i].time<<endl;
    	}
    } 
    int find() //找到最久未置换或者空页块 
    {
    	int nu=0; 
    	for(int i=0;i<n;i++)
    	{
    		if(page[i].num==-1) 
    		{
    			nu=i;
    			return nu;
    			break;
    		}
    	}
    	int max=0,maxnum=0;
    	for(int i=0;i<n;i++)
    	{
    		if(page[i].time>max)
    		{
    			max=page[i].time;
    			maxnum=i;
    		}
    	}
    	return maxnum;
    } 
    void run() //时间加1 
    {
    	for(int i=0;i<n;i++) 
    	{
    		if(page[i].num!=-1) page[i].time++;
    	}
    }
    void change(memory page[],int xulie[]) //页块分配 
    {
    	for(int i=0;i<m;i++)
    	{
    		bool fa=true;
    		for(int j=0;j<n;j++) //命中 
    		{
    			if(page[j].num==xulie[i])
    			{
    				fa=false;
    				page[j].time=-1;
    				run();
    				print();
    				break;
    			} 
    		}
    		if(fa==true) //不命中 
    		{
    			count++;
    			int j=find();
    			page[j].num=xulie[i];
    			page[j].time=-1;
    			run();
    			print();
    		}
    	}
    }
    int main()
    {
    	int xulie[100];
    	cout << "分配给进程的页块数为:";
    	cin >> n;
    	cout<< "请输入页面访问序列长度:";
    	cin >> m;
    	for(int i=0;i<n;i++) //页块初始化 
    	{
    		page[i].num=-1;
    		page[i].time=0;
    	}
    	cout<<"页面访问序列为";
    	for (int i = 0; i < m; i++)	
    	{
    		xulie[i] = rand()%10;
    		cout<<xulie[i]<<" ";
    	}
    	cout<<endl;
    	change(page,xulie);
    	double queyelv=count*1.000/m;
    	cout<<"缺页次数:"<<count<<endl<<"缺页率:"<<queyelv; 
    }
    
    
    更多相关内容
  •  当内存块数量分别为3时,试问FIFO、LRU、OPT这三种置换算法的缺页次数各是多少?  答:缺页定义所有内存块最初都是空的,所以第一次用到的页面都产生一次缺页。  当内存块数量为3时


    考虑下述页面走向:

              12342156212376321236

         当内存块数量分别为3时,试问FIFOLRUOPT这三种置换算法的缺页次数各是多少?

       答:缺页定义为所有内存块最初都是空的,所以第一次用到的页面都产生一次缺页。

           当内存块数量为3时:




    发生缺页中断的次数为16

      在FIFO算法中,先进入内存的页面被先换出。当页6要调入时,内存的状态为415,考查页6之前调入的页面,分别为5124,可见4为最先进入内存的,本次应换出,然后把页6调入内存。


    发生缺页中断的次数为15

      在LRU算法中,最近最少使用的页面被先换出。当页6要调入时,内存的状态为521,考查页6之前调入的页面,分别为512,可见2为最近一段时间内使用最少的,本次应换出,然后把页6调入内存。




    发生缺页中断的次数为11

        在OPT算法中,在最远的将来才被访问的页面被先换出。当页6要调入时,内存的状态为125,考查页6后面要调入的页面,分别为212,可见5为最近一段时间内使用最少的,本次应换出,然后把页6调入内存。


    OPT算法因为要知道后面请求的页框,因此我觉得这个算法有个小小的bug,如果在某个请求中,若在该请求的页框之后的页框序列中至少存在一个和当前内存块中不匹配的页框,则按照内存块的顺序(从上往下)替换没有出现的页框。比如上面那个OPT例子。对于最后一个页框请求,因为6未命中,且6之后没有请求的序列,因此应该替换3,所以替换后的序列为6 , 2 ,1   当然,这只是针对做题而言。


    展开全文
  •  当内存块数量分别为3时,试问FIFO、LRU、OPT这三种置换算法的缺页次数各是多少?  答:缺页定义所有内存块最初都是空的,所以第一次用到的页面都产生一次缺页。  当内存块数量为3时:  发生缺页中断的次数...
    考虑下述页面走向:
      1,2,3,4,2,1,5,6,2,1,2,3,7,6,3,2,1,2,3,6
      当内存块数量分别为3时,试问FIFO、LRU、OPT这三种置换算法的缺页次数各是多少?
      答:缺页定义为所有内存块最初都是空的,所以第一次用到的页面都产生一次缺页。
       当内存块数量为3时:
      发生缺页中断的次数为16。
      在FIFO算法中,先进入内存的页面被先换出。当页6要调入时,内存的状态为4、1、5,考查页6之前调入的页面,分别为5、1、2、4,可见4为最先进入内存的,本次应换出,然后把页6调入内存。
      发生缺页中断的次数为15。
      在LRU算法中,最近最少使用的页面被先换出。当页6要调入时,内存的状态为5、2、1,考查页6之前调入的页面,分别为5、1、2,可见2为最近一段时间内使用最少的,本次应换出,然后把页6调入内存。
      发生缺页中断的次数为11。
      在OPT算法中,在最远的将来才被访问的页面被先换出。当页6要调入时,内存的状态为1、2、5,考查页6后面要调入的页面,分别为2、1、2、…,可见5为最近一段时间内使用最少的,本次应换出,然后把页6调入内存。
      OPT算法因为要知道后面请求的页框,因此我觉得这个算法有个小小的bug,如果在某个请求中,若在该请求的页框之后的页框序列中至少存在一个和当前内存块中不匹配的页框,则按照内存块的顺序(从上往下)替换没有出现的页框。比如上面那个OPT例子。对于最后一个页框请求,因为6未命中,且6之后没有请求的序列,因此应该替换3,所以替换后的序列为6 , 2 ,1   当然,这只是针对做题而言。


    最新内容请见作者的GitHub页:http://qaseven.github.io/

    展开全文
  • 一种高效的 C++ 固定内存块分配器

    千次阅读 2017-02-14 20:26:19
    英文原文:An Efficient C++ Fixed Block Memory Allocator 翻译作者:码农网 – 苏文鹏 简介 ...自定义固定内存块分配器用于解决两种类型的内存问题。第一,全局堆内存的分配和释放非常慢而且是

    译文链接:http://www.codeceo.com/article/efficient-cpp-memory-allocator.html
    英文原文:An Efficient C++ Fixed Block Memory Allocator
    翻译作者:码农网 – gunner

    简介

    自定义固定内存块分配器用于解决两种类型的内存问题。第一,全局堆内存的分配和释放非常慢而且是不确定的。你不能确定内存管理需要消耗多长时间。第二,降低由堆内存碎片(对于执行关键操作的系统尤为重要)造成的内存分配失败的可能性。

    即使不是执行关键操作的系统,一些嵌入式系统也需要被设计成需要运行数周甚至数年而不重启。取决于内存分配的模式和堆内存的实现方式,长时间的使用堆内存可能导致堆内存错误。

    典型的解决方案是预先静态声明所有对象的内存,从而摆脱动态申请内存。然而,由于对象即使没有被使用,也已经存在并占据一部分内存,静态分配内存的方式会浪费内存存储。此外,使用动态内存分配方式实现的系统提供更为自然的设计框架,而不像静态内存分配需要事先分配所有对象。

    固定内存块分配器并不是一种新的方法。人们已经设计过多种自定义内存分配器很长时间了。这里,我提供的是我在很多项目中成功使用的,一种简单的C++内存分配器的实现。

    这种分配器的实现具有如下特点:

    • 比全局堆内存速度快
    • 消除堆内存碎片错误
    • 不需要额外的内存存储(除了需要几个字节的静态内存)
    • 易于使用
    • 代码量很小

    这里将提供一个申请、释放内存的,包含上面所提到特点的简单类。

    阅读完此文后,请同时阅读Replace malloc/free with a Fast Fixed Block Memory Allocator,查看如何使用分配器Allocator替代CRT(C/C++ Runtime Library)。

    回收内存存储

    内存管理模式的基本哲学是在对象内存分配时能够回收内存。一旦在内存中创建了一个对象,它所占用的内存就不能被重新分配。同时,内存要能够回收,允许相同类型的对象重用这部分内存。我实现了一个名为Allocator的类来展示这些技巧。

    当应用程序使用Allocator类进行删除时,对象占用的内存空间被释放以备重用,但却不会立即释放给内存管理器,这些内存保留在就一个称之为“释放列表”的链表中,并再次分配给相同类型的对象。对每个内存分配的请求,Allocaor类首先检查“释放列表”中是否存在待释放的内存。只有“释放列表”中没有可用的内存空间时才会分配新的内存。根据所需的Allocator类的行为,内存存储以三种操作模式使用全局堆内存或者静态内存池。

    • 1.堆内存
    • 2.堆内存池
    • 3.静态内存池

    堆内存 vs. 内存池

    Allocator类在“释放列表”为空时,能够从堆内存或者内存池中申请新内存。如果使用内存池,你必须事先确定好对象的数量。确保内存池足够容纳所有需要使用的对象。另一方面,使用堆内存没有数量大小的限制——可以构造内存允许的尽可能多的对象。

    堆内存模式在全局堆内存上为对象分配内存。释放操作将这块内存放入“释放了列表”以备重用。当“释放列表”为空时,需要在堆内存上创建新内存。这种方式提供了动态内存的分配和释放,优点是内存块可以在运行时动态增加,缺点是内存块创建期间是不确定的,可能创建失败。

    堆内存池模式从全局堆内存创建一个内存池。当Allocator类对象创建时,使用new操作符创建内存池。然后使用内存池中的内存块进行内存分配。

    静态内存池模式使用从静态内存中分配的内存池。静态内存池由使用者进行分配而不是由Allocator对象进行创建。

    堆内存池模式和静态内存池模式提供了内存操作的连续使用,因为内存分配器不需要分配单独的内存块。这样分配内存的过程是十分快速且具有确定性的。

    类设计

    类的接口很简单。Allocate()返回指向内存块的指针,Deallocate()释放内存以备重用。构造函数需要设置对象的大小,并且如果使用内存池,需要分配内存池空间。

    类的构造函数中的参数用于决定内存块分配的位置。size参数控制固定内存块的大小。objects参数设置申请内存块的个数,其值为0表示从堆内存中申请新内存块,非0表示使用内存池方式(堆内存池或者静态内存池)分配对象实例空间。memory参数是指向静态内存的指针。如果memory等于0并且objects非零,Allocator将从堆内存中创建一个内存池。静态内存池内存大小必须是size*object字节。name参数为内存分配器命名,用于收集分配器使用信息。

    class Allocator
    {
    public:
        Allocator(size_t size, UINT objects=0, CHAR* memory=NULL, const CHAR* name=NULL);
    ...

    下面的例子展示三种分配器模式中的构造函数是如何赋值的。

    // Heap blocks mode with unlimited 100 byte blocks
    Allocator allocatorHeapBlocks(100);
    
    // Heap pool mode with 20, 100 byte blocks
    Allocator allocatorHeapPool(100, 20);
    
    // Static pool mode with 20, 100 byte blocks
    char staticMemoryPool[100 * 20];
    Allocator allocatorStaticPool(100, 20, staticMemoryPool);

    为了简化静态内存池方法,提供AllocatorPool<>模板类。模板的第一个参数设置申请内存对象类型,第二个参数设置申请对象的数量。

    // Static pool mode with 20 MyClass sized blocks 
    AllocatorPool<MyClass, 20> allocatorStaticPool2;

    Deallocate()将内存地址放入“栈”中。这个“栈”的实现方式类似于单项链表(“释放列表”),但是只能添加、移除头部的对象,其行为类似栈的特性。使用“栈”使得分配、释放操作更为快速,因为不需要全链表遍历而只需要压入和弹出操作。

    void* memory1 = allocatorHeapBlocks.Allocate(100);

    这样便在不增加额外存储的情况下,将内存块链接在“释放列表”中。例如,当我们使用全局operate new时,首先申请内存,然后调用构造函数。delete的过程与此相反,首先调用析构函数,然后释放掉内存。调用完析构函数后,在内存释放给堆之前,这块内存不再被原有的对象使用,而是放到“释放列表”中以备重用。由于Allocator类需要保存已经释放的内存块,在使用delete操作符时,我们将“释放列表”中的下一个指针指向这个被delete的对象内存地址。当应用程序再次使用这块内存时,指针被覆写为对象的地址。通过这种方法,就不需要预先实例化内存空间。

    使用释放对象的内存来将内存块连接在一起意味着对象的内存空间需要足够容纳一个指针占用内存空间的大小。构造函数初始化列表中的代码保证了最小内存块大小不会小于指针占用内存块的大小。

    类的析构函数通过释放堆内存池或者遍历“释放列表”并逐个释放内存块来实现内存的释放。由于Allocator类对象常被用作是static的,那么Allocator对象的释放是在程序结束时。对于大多数嵌入式设备,应用只在人们拔断电源时才会结束。因此,对于这种嵌入式设备,析构函数的作用就显无所谓了。

    如果使用堆内存块模式,除非所有分配的内存被链接在“释放列表”,应用结束时分配的内存块不能被释放。因此,所有对象应该在程序结束时被“删除”(指放入“释放列表”)。这似乎是内存泄漏,也带来了一个有趣的问题。Allocator应该跟踪正在使用和已经释放的内存块吗?答案是否定的。以为一旦一块内存通过指针被应用所使用,那么应用程序有责任在程序结束前通过调用Deallocate()返回该内存块指针给Allocator。这样的话,我么只需要跟踪释放的内存块。

    代码的使用

    Allocator易于使用,因此创建宏来自动在客户端类中实现接口。宏提供一个静态类型的Allocator实例和两个成员函数:操作符new和操作符delete。通过重写new和delete操作符,Allocator截取并处理所有的客户端类的内存分配行为。

    DECLARE_ALLOCATOR宏提供头文件接口,并且应该在类定义时将其包含在内,如下面这样:

    #include "Allocator.h"
    class MyClass
    {
        DECLARE_ALLOCATOR
        // remaining class definition
    };

    操作符new函数调用Allocator创建类实例所需要的内存空间。内存分配后,根据定义,操作符new调用该类的构造函数。重写的new只修改了内存的分配任务。构造函数的调用由语言保证。删除对象时,系统首先调用析构函数,然后调用执行操作符delete函数。操作符delete使用Deallocate()函数将内存块加入到“释放列表”中。

    尽管没有明确声明,操作符delete是静态函数(静态函数才能调用静态成员)。因此它不能被声明为virtual。这样看上去通过基类的指针删除对象不能达到删除真实对象的目的。毕竟,调用基类指针的静态函数只会调用基类的成员函数,而不是其真实类型的成员函数。然而,我们知道,调用操作符delete时首先调用析构函数。修饰为virtual的析构函数会实际调用子类的析构函数。类的析构函数执行完后,子类的操作符delete函数被调用。因此实际上,由于虚析构函数的调用,重写的操作符delete会在子类中调用。所以,使用基类指针删除对象时,基类对象的析构函数必须声明为virtual。否则,将会不能正确调用析构函数和操作符delete。

    IMPLEMENT_ALLOCATOR宏是接口的源文件实现部分,并应该放置于源文件中。

    IMPLEMENT_ALLOCATOR(MyClass, 0, 0)

    使用上述宏后,可以如下面一样创建并销毁类的实例,同事循环使用释放的内存空间。

    MyClass* myClass = new MyClass();
    delete myClass;

    Allocator类支持单继承和多继承。例如,Derived类继承Base类,如下代码是正确的。

    Base* base = new Derived;
    delete base;

    运行时

    运行时,Allocator初始化时“释放列表”中没有可重用的内存块。因此,第一次调用Allocate()将从内存池或者堆中获取内存空间。随着程序的执行,系统不断使用对象会造成分配器的波动。并且只有当释放列表无法提供内存时,新内存才会被申请和创建。最终,系统使用对象的实例会固定,因此每次内存分配将会使用已经存在的内存空间二不是再从内存池或者堆中申请。

    与使用内存管理器分配所有对象内存相比,Allocator分配器更加高效。内存分配时,内存指针仅仅是从“释放列表”中弹出,速度非常快。内存释放时也仅仅是将内存指针放入到“释放列表”当中,速度也十分快。

    基准测试

    在Windows PC上使用Allocator和全局堆内存的对比性能测试显示出Allocator的高性能。测试分配和释放20000个4096和2048大小的内存块来测试分配和释放内存的速度。测试的算法详见附件中的代码。

    Allocator Mode Run Benchmark Time (mS)
    Global Heap Debug Heap 1 1640
    Global Heap Debug Heap 2 1864
    Global Heap Debug Heap 3 1855
    Global Heap Release Heap 1 55
    Global Heap Release Heap 2 47
    Global Heap Release Heap 3 47
    Allocator Static Pool 1 19
    Allocator Static Pool 2 7
    Allocator Static Pool 3 7
    Allocator Heap Blocks 1 30
    Allocator Heap Blocks 2 7
    Allocator Heap Blocks 3 7

    使用调试模式执行时,Windows使用调试堆内存。调试堆内存添加额外的安全检查降低了性能。发布堆内存性能更好,因为不使用安全检查。通过在Visual Studio工程选项中,设置【调试】-【环境】中_NO_DEBUG_HEAP=1来禁止调试内存模式。

    全局调试堆内存模式需要平均1.8秒,是最慢的。释放对内存模式50毫秒左右,稍快。基准测试的场景非常简单,实际情况下,不同大小的内存块和随机的申请、释放可能产生不同的结果。然而,最简单的也最能说明问题。内存管理器比Allocator内存分配器慢,并且很大程度上依赖于平台的实现能力。

    内存分配器Allocator使用静态内存模式不依赖于堆内存的分配。一旦“释放列表”中含有内存块后,其执行时间大约为7毫秒。第一次耗时19毫秒用于将内存池中的内存防止到Allocator分配器中管理。

    Aloocator使用堆内存模式时,当“释放列表”中有可重用的内存后,其速度与静态内存模式一样快。堆内存模式依赖于全局堆来获取内存块,但是循环利用“释放列表”中的内存。第一次需要申请堆内存,耗时30毫秒。由于重用“释放列表”中的内存,之后的申请仅需要7毫秒。

    上面的基准测试结果表示,Allocator内存分配器更加高效,拥有7倍于Windows全局发布堆内存模式的速度。

    对于嵌入式系统,我使用Keil在ARM STM32F4 CPU(168Hz)上运行相同测试。由于资源限制,我将最大内存块数量降低到500,单个内存块大小降低到32和16字节。下面是结果:

    Allocator Mode Run Benchmark Time (mS)
    Global Heap Release 1 11.6
    Global Heap Release 2 11.6
    Global Heap Release 3 11.6
    Allocator Static Pool 1 0.85
    Allocator Static Pool 2 0.79
    Allocator Static Pool 3 0.79
    Allocator Heap Blocks 1 1.19
    Allocator Heap Blocks 2 0.79
    Allocator Heap Blocks 3 0.79

    基于ARM的基准测试显示,使用Allocator分配器的类性能快15倍。这个结果会让Keil堆内存的表现相形见绌。基准测试分配500个16字节大小的内存块进行测试。每个16字节大小的内存删除后申请500个32字节大小的内存块。全局堆内存耗时11.6毫秒,而且,在内存碎片化后,内存管理器可能会在没有安全检查的情况下耗时更大。

    分配器决议

    第一个决定是你是否需要使用分配器。如果你的项目不关心执行的速度和是否需要容错,那么你可能不需要自定义的分配器,全局堆分配管理器足够用了。

    另一方面,如果你需要考虑执行速度和容错管理,分配器会起到作用。你需要根据项目的需要选择分配器的模式。重要任务系统的设计可能强制要求使用全局堆内存。而动态分配内存可能更高效,设计更优雅。这种情况下,你可以在调试开发时使用堆内存模式获取内存使用参数,然后发布时切换到静态内存池模式避免内存分配带来的性能消耗。一些编译时的宏可用于模式的切换。

    另外,堆内存模式可能对应用更适合。该模式利用堆来获取新内存,同时阻止了堆碎片错误。当“释放列表”链接足够的内存块后更能加快内存的分配效率。

    在源代码中没有实现的涉及多线程的问题不在本文的讨论范围内。运行系统一会后,可以方便地使用GetlockCount函数和GetName函数获取内存块数量和名称。这些度量参数提供关于内存分配的信息。尽量多申请点内存,以便给分配盘一些弹性来避免内存耗尽。

    调试内存泄漏

    调试内存泄漏非常困难,原因是堆内存就像一个黑盒,对于分配对象的类型和大小是不可见的。使用Allocator,由于Allocator跟踪记录内存块的总数,内存泄漏检查变得简单一点。对每个分配器实例重复输出(例如输出到终端)GetBlockCount和GetName并比对它们的不同能让我们更好的了解分配器对内存的分配。

    错误处理

    C++中使用new_handler函数处理内存分配错误。如果内存管理器在申请内存时发生错误,用户的错误处理函数就会被调用。通过将用户的错误处理函数地址复制给new_handler,内存管理器就能调用用户自定义的错误处理程序。为了让Allocator类的错误处理机制与内存管理器保持一致,分配器也通过new_handler调用错误处理函数,集中处理所有的内存分配错误。

    static void out_of_memory()
    {
        // new-handler function called by Allocator when pool is out of memory
        assert(0);
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        std::set_new_handler(out_of_memory);
    ...

    限制

    分配器类不支持数组对象的内存分配。为每一个对象创建分开的内存是无法保证的,因为new的多次调用不保证内存块的连续,但这又是数组所需要的。因此Allocator只支持固定大小内存块的分配,对象数组不支持。

    移植问题

    Allocator在静态内存池耗尽时调用new_handle指向的函数,这对于某些系统不合适。假设new_handle函数没返回,例如无尽的循环或者断言,调用这个函数不起任何作用。使用固定内存池时这无济于事。

    进一步阅读

    请阅读相关文章:使用快速固定大小分配器替换malloc/free来查看如何使用Allocator更为快速的替换C++运行工具中的malloc和free函数。

    下载源码:Download Allocator.zip – 5.4 KB


    展开全文
  • FIFO和LRU计算缺页中断

    千次阅读 2015-03-15 19:50:23
    在一个请求分页面管理中,一个程序的页面走向1、2、3、4、1、...当内存块数量为3时,试问使用 (1)FIFO页面置换算法 (2)LRU页面置换算法 (开始没有装入页面)的缺页中断次数是多少() FIFO: 页 4 1 2 5 1 2
  • 页面置换算法(LRU算法)

    万次阅读 多人点赞 2018-08-24 10:58:08
    LRU是一种页面置换算法,在对于内存中但是又不用的数据,叫做LRU,操作系统会根据那些数据属于LRU而将其移出内存而腾出空间来加载另外的数据 LRU算法:最近最少使用,简单来说就是将数据中,每次使用过的数据...
  • 有一个虚拟存储系统,若进程在内存中占3页(开始时内存为空),若采用先进先出(FIFO)页面淘汰算法,执行如下访问页号序列后1,2,3,4,5, 1,2,5,1,2,3,4,5,会发生多少缺页?A:7 B:8 C:9 D:10...
  • 一文看懂JVM运行时内存分布

    千次阅读 多人点赞 2021-11-26 16:03:40
    前言 繁忙的一年即将过去,由于若干种原因,下定决心开始写一些基础系列,主要...从1+2等3来看JVM运行时内存分布 新建一个Test类,定义一个静态方法sum,代码如下所示: public class Test { public static voi.
  • 深入理解Java虚拟机-Java内存区域与内存溢出异常

    万次阅读 多人点赞 2020-01-03 21:42:24
    文章目录概述运行数据区域程序计数器(线程私有)Java虚拟机栈(线程私有)局部变量表操作数栈动态链接方法返回地址小结本地方法栈(线程私有)Java堆(全局共享)方法区(全局共享)运行常量池直接内存HotSpot...
  • 面试必问:Java 内存模型的3个特性

    千次阅读 2020-04-28 19:29:07
    Java内存模型(Java Memory Model ,JMM)就是一种符合内存模型规范的,屏蔽了各种硬件和操作系统的访问差异的,保证了Java程序在各种平台下对内存的访问都能得到一致效果的「机制及规范」。 JMM与Java内存区域是两...
  • 基础面试3内存溢出 vs 内存泄漏

    万次阅读 2020-11-16 11:38:45
    内存泄露 memory leak:内存泄漏指程序运行过程中分配内存给临时变量,用完之后却没有被GC回收,始终占用着内存,既不能被使用也不能分配给其他程序,于是就发生了内存泄漏。 举个例子 油罐里的资源(石油)被人偷了...
  • 疑难杂症:申请点内存为何这么耗时

    千次阅读 热门讨论 2021-04-10 20:21:21
    本次我们继续生产问题的疑难杂症排查系统的文章,在开始我们下一次集中讨论Redis的问题之前,还需要用两次博客来专门讲一下有关于内存的问题,本文先行讨论一下内存分配的时间复杂度,下一篇计划叫《疑难杂症:内存...
  • iOS之深入解析文件内存映射MMAP

    万次阅读 热门讨论 2021-08-31 19:33:16
    失败,mmap() 返回 MAP_FAILED [其值 (void *)-1], error 被设以下的某个值: 1 EACCES:访问出错 2 EAGAIN:文件已被锁定,或者太多的内存已被锁定 3 EBADF:fd不是有效的文件描述词 4 EINVAL:一...
  • 【Linux】Linux的内核空间(低端内存、高端内存

    万次阅读 多人点赞 2018-07-20 16:50:01
    内核也是程序,也应该具有自己的虚存空间,但是作为一种用户程序服务的程序,内核空间有它自己的特点。   内核空间与用户空间的关系 在一个32位系统中,一个程序的虚拟空间最大可以是4GB,那么最直接的做法...
  • 存储管理的页面置换算法

    千次阅读 2014-03-28 20:25:19
    存储管理的页面置换算法 存储管理的页面置换算法在考试中常常会考到,操作系统教材中主要介绍了3种常用的页面置换算法...什么要进行页面置换 在请求分页存储管理系统中,由于使用了虚拟存储管理技术,
  • 本次我们继续生产问题的疑难杂症排查系统的文章,在开始我们下一次集中讨论Redis的问题之前,本文与《疑难杂症:系统雪崩到底是什么》和《疑难杂症: 遇到一个杀不掉,追不到,找不着的进程怎么破?》共同作为下次...
  • Java内存模型

    万次阅读 多人点赞 2019-10-04 15:09:15
    Java内存模型(JMM)的介绍 在上一篇文章中总结了线程的状态和基本操作,对多线程已经有一点基本的认识了,如果多线程编程只有这么简单,那我们就不必费劲周折的去学习它了。在多线程中稍微不注意就会出现线程安全...
  • Linux下查看某一进程占用的内存

    千次阅读 2021-11-01 14:56:25
    Linux下查看某一个进程所占用的内存,首先可以通过ps命令找到进程id,比如:ps -ef|grep flink,可以看到flink task这个程序的进程id 已知pid是8678,现在可以使用如下命令查看内存: 这样可以动态实时的看到...
  • linux内存管理(十五)-内存

    千次阅读 2021-07-14 09:15:54
    平时我们直接所使用的 malloc,new,free,delete 等等 API 申请内存分配,这做缺点在于,由于所申请内存块的大小不定,频繁使用会造成大量的内存碎片并进而降低性能。 memory pool 是一种内存分配方式,又被称为...
  • 面试官:说说什么是 Java 内存模型(JMM)?

    万次阅读 多人点赞 2021-05-05 23:23:20
    1. 什么要有内存模型? 1.1. 硬件内存架构 1.2. 缓存一致性问题 1.3. 处理器优化和指令重排序 2. 并发编程的问题 3. Java 内存模型 3.1. Java 运行时内存区域与硬件内存的关系 3.2. Java 线程与主内存的关系 ...
  • 内存满足你的场景文件所需要的量,渲染的时候除了灯光计算需要比较多的内存以外其余几乎不消耗内存。普通场景一般1G内存够用了。也就是说,对于一个场景的渲染,如果1G内存够了,不会调用硬盘做虚拟内存的情况...
  • 关于多指针指向同一块内存的问题

    千次阅读 2017-09-15 15:19:12
    有时为了逻辑实现的方便,在程序中会采用多指针指向同一块内存的设计,但是这同时会带来问题: 问题1:容易引发“野指针”错误!即其中一个指针delete了内存之后,其他指针无法判断该指向地址是否还有效,如果也去...
  • 堆的内存管理简介

    千次阅读 2022-02-14 00:17:22
    目录 堆的概述 堆的操作 brk、mmap函数 调用过程 ...参考:进程分配内存的两种方式--brk() 和mmap()(不设计共享内存)_鱼思故渊的专栏-CSDN博客_mmap分配...堆其实就是程序虚拟地址空间的一连续的线性区域,它由
  • 实现一个高并发内存池-----对比Malloc

    千次阅读 多人点赞 2019-05-25 16:18:27
    其内涵在于:将程序中需要经常使用的核心资源先申请出来,放到一个池内,有程序自管理,这样可以提高资源的利用率,也可以保证本程序占有的资源数量,经常使用的池化技术包括内存池,线程池,和连接池等,其中尤以...
  • 操作系统笔记——基本分页式内存管理

    千次阅读 多人点赞 2020-10-16 00:58:25
    操作系统把内存划分大小一样的若干(其实多得多)个,每个相对较小,作为内存的基本单位,进程在申请内存时,也是以块为单位逐个申请空间。 二、分页管理的特点 ① 分页管理不会出现外部碎片。 ② 由于进程...
  • 解析一个Java对象占用多少内存空间

    万次阅读 2019-07-13 16:02:15
    说明: alignment, 对齐, 比如8字节的数据类型long, 在内存中的起始地址必须是8的整数倍。 padding, 补齐; 在对象所占据空间的末尾,如果有空白, 需要使用padding来补齐, 因为下一个对象的起始位置必须是4/8字节(32bit...
  • 内存溢出分析之工具篇

    千次阅读 2018-09-28 16:26:57
    主要介绍 性能压测工具 jmeter;JDK 自带工具JConsole、JVisualVM;google 推出的 malloc 分析工具 gperftools;eclipse 的 dump 文件分析工具 MAT;sun 推出的 Java 动态追踪...linux 查看进程内存软件 gdb 等的使用

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 359,668
精华内容 143,867
热门标签
关键字:

当内存块数量为3时

友情链接: Rendezvous.zip