Android Dalvik虚拟机 对象创建内存分配流程

news2024/9/24 15:22:39

前言

本篇文章介绍我们在日常开发使用Java时new对象的时,Dalvik在堆上的内存分配是如何分配的。内存又和gc相关,下篇文章会分析Dalvik的gc流程。

Dalvik内存管理

内存碎片问题其实是一个通用的问题,不单止Dalvik虚拟机在Java堆为对象分配内存时会遇到,C库的malloc函数在分配内存时也会遇到。Android系统使用的C库bionic使用了Doug Lea写的dlmalloc内存分配器。也就是说,我们调用函数malloc的时候,使用的是dlmalloc内存分配器来分配内存。
Dalvik虚拟机的Java堆的底层实现是一块匿名共享内存,并且将其抽象为C库的一个mspace,即Dalvik虚拟机是利用的C库里面的dlmalloc内存分配器来解决内存碎片问题。
从Dailvk代码设计上存在两种内存限制,这两种限制在随着内存分配堆增长的过程中在不断调整,本篇文章分析内存分配流程,有机会分析内存管理这块,即Dalvik是如何调整堆的算法的,也比较复杂:

  1. 一是Dalvik设计的softLimit,即在Active堆中可以分配的内存上限;
  2. 二是mspace的hardLimit限制,即是匿名共享内存里的mspace_footprint限制;

对象创建内存分配流程

  1. Java中进行对象分配最终会通过tryMalloc进行内存分配
  2. tryMalloc操作的核心方法是dvmHeapSourceAlloc和dvmHeapSourceAllocAndGrow
  3. tryMalloc中,首次调用dvmHeapSourceAlloc进行分配,此时如果分配成功,超过concurrentStartBytes时则会触发concurrent gc,此为并发gc,较为轻量级
  4. dvmHeapSourceAlloc分配失败的原因可以是softlimit或mspace的footprint达到阈值
  5. 在首次执行dvmHeapSourceAlloc失败后触发GC_FOR_MALLOC进行同步内存回收,是stop world类型gc,最为耗时
  6. 如果此时还失败的话,会尝试调用dvmHeapSourceAllocAndGrow,先remove掉softLimt尝试分配,不行的话再把footprint增到最大再分配,分配完成后会将footprint还原
  7. 如果调用dvmHeapSourceAllocAndGrow仍然失败,那么会触发GC_BEFORE_OOM进行回收,这里传入参数true表示也要讲软引用一块清除掉了
  8. 软引用清除掉后之后再会尝试dvmHeapSourceAllocAndGrow,如果还是失败,那么会抛出OutOfMemoryError错误
    在这里插入图片描述

Heap.cpp

dvmMalloc

Java的动态内存分配是通过new操作符完成的,而最终调用的是dvmMalloc()函数,Dalvik在内存分配上也在尽力分配出内存,直到最后OOM。

// Allocate storage on the GC heap.  We guarantee 8-byte alignment.
void* dvmMalloc(size_t size, int flags)
{
    void *ptr;

    dvmLockHeap();
    // Try as hard as possible to allocate some memory.
    ptr = tryMalloc(size);
    dvmUnlockHeap();

    if (ptr != NULL) {
        // track it,此处在下篇文章分析,这里可以dump出来分配的内存和堆栈
        if ((flags & ALLOC_DONT_TRACK) == 0) {
            dvmAddTrackedAlloc((Object*)ptr, NULL);
        }
    } else {
        // The allocation failed; throw an OutOfMemoryError.
        throwOOME();
    }

    return ptr;
}

tryMalloc

// Try as hard as possible to allocate some memory.
static void *tryMalloc(size_t size)
{
    void *ptr;
    ptr = dvmHeapSourceAlloc(size);
    if (ptr != NULL) {
        return ptr;
    }

    // The allocation failed.  If the GC is running, block until it completes and retry.
    if (gDvm.gcHeap->gcRunning) {
        // The GC is concurrently tracing the heap.  Release the heap lock, wait for the GC to complete, and retrying allocating.
        dvmWaitForConcurrentGcToComplete();
    } else {
      // Try a foreground GC since a concurrent GC is not currently running.
      gcForMalloc(false); 
    }

    ptr = dvmHeapSourceAlloc(size);
    if (ptr != NULL) {
        return ptr;
    }

    // Even that didn't work;  this is an exceptional state. Try harder, growing the heap if necessary.
    ptr = dvmHeapSourceAllocAndGrow(size);
    if (ptr != NULL) {
    	// may want to grow a little bit more so that the amount of free space is equal to the old free space + the utilization slop for the new allocation.
        size_t newHeapSize;
        newHeapSize = dvmHeapSourceGetIdealFootprint();
        return ptr;
    }

    /* Most allocations should have succeeded by now, so the heap
     * is really full, really fragmented, or the requested size is
     * really big.  Do another GC, collecting SoftReferences this
     * time.  The VM spec requires that all SoftReferences have
     * been collected and cleared before throwing an OOME.
     */
    gcForMalloc(true);
    ptr = dvmHeapSourceAllocAndGrow(size);
    if (ptr != NULL) {
        return ptr;
    }
    dvmDumpThread(dvmThreadSelf(), false);
    return NULL;
}

HeapSouce.cpp

dvmHeapSourceAlloc

// Allocates <n> bytes of zeroed data.
void* dvmHeapSourceAlloc(size_t n) {
    HeapSource *hs = gHs;
    Heap* heap = hs2heap(hs);

    if (heap->bytesAllocated + n > hs->softLimit) {
        // softLimit限制;This allocation would push us over the soft limit; act as if the heap is full.
        return NULL;
    }
    void* ptr = mspace_calloc(heap->msp, 1, n);
    if (ptr == NULL) {
    	// hardLimit限制
    	return NULL;
    }

    countAllocation(heap, ptr);
    // Check to see if a concurrent GC should be initiated. The garbage collector thread is already running or has yet to be started.  Do nothing.
    if (gDvm.gcHeap->gcRunning || !hs->hasGcThread) {
        return ptr;
    }
    // 唤醒concurrent gc. We have exceeded the allocation threshold.  Wake up the garbage collector.
    if (heap->bytesAllocated > heap->concurrentStartBytes) {
        dvmSignalCond(&gHs->gcThreadCond);
    }
    return ptr;
}

dvmHeapSourceAllocAndGrow

// Allocates <n> bytes of zeroed data, growing as much as possible if necessary.
void* dvmHeapSourceAllocAndGrow(size_t n) {
    HeapSource *hs = gHs;
    Heap* heap = hs2heap(hs);
    void* ptr = dvmHeapSourceAlloc(n);
    if (ptr != NULL) {
        return ptr;
    }

    size_t oldIdealSize = hs->idealSize;
    // We're soft-limited.  Try removing the soft limit to see if we can allocate without actually growing.
    if (isSoftLimited(hs)) {
        hs->softLimit = SIZE_MAX;
        ptr = dvmHeapSourceAlloc(n);
        if (ptr != NULL) {
            snapIdealFootprint();
            return ptr;
        }
    }

    // We're not soft-limited.  Grow the heap to satisfy the request. If this call fails, no footprints will have changed.
    ptr = heapAllocAndGrow(hs, heap, n);
    if (ptr != NULL) {
        snapIdealFootprint();
    } else {
        setIdealFootprint(oldIdealSize);
    }
    return ptr;
}


// Remove any hard limits, try to allocate, and shrink back down. Last resort when trying to allocate an object.
static void* heapAllocAndGrow(HeapSource *hs, Heap *heap, size_t n)
{
    // Grow as much as possible, but don't let the real footprint go over the absolute max.
    size_t max = heap->maximumSize;
    mspace_set_footprint_limit(heap->msp, max);
    
    void* ptr = dvmHeapSourceAlloc(n);

    // Shrink back down as small as possible.  Our caller may readjust max_allowed to a more appropriate value.
    mspace_set_footprint_limit(heap->msp, mspace_footprint(heap->msp));
    
    return ptr;
}

Dalvik虚拟机为新创建对象分配内存的过程分析

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/340735.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python中的类和对象(7)

1.私有变量 在大多数面向对象的编程语言中&#xff0c;都存在着私有变量&#xff08;private variable&#xff09;的概念&#xff0c;所谓私有变量&#xff0c;就是指通过某种手段&#xff0c;使得对象中的属性或方法无法被外部所访问。 Python 对于私有变量的实现是引入了一…

MySQL数据库调优————数据库调优维度及测试数据准备

MySQL性能优化金字塔法则 不合理的需求&#xff0c;会造成很多问题。&#xff08;比如未分页&#xff0c;数据需要多表联查等&#xff09;做架构设计的时候&#xff0c;应充分考虑业务的实际情况&#xff0c;考虑好数据库的各种选择&#xff08;比如是否要读写分离&#xff0c;…

Spring IOC Bean标签属性介绍(内含教学视频+源代码)

Spring IOC Bean标签属性介绍&#xff08;内含教学视频源代码&#xff09; 教学视频源代码下载链接地址&#xff1a;https://download.csdn.net/download/weixin_46411355/87442649 目录Spring IOC Bean标签属性介绍&#xff08;内含教学视频源代码&#xff09;教学视频源代码…

jetson nano(ubuntu)安装Cmake

文章目录安装环境一.命令行安装二.Cmake源码编译安装安装环境 jetson nano 系统&#xff1a;4.6.1 一.命令行安装 sudo apt install cmake这种直接安装cmake的方式&#xff0c;其实安装的版本都太老了&#xff0c;这种方式不推荐 二.Cmake源码编译安装 更新一下系统软件 su…

子词嵌入,词的相似性和类比任务

fastText模型提出了一种子词嵌入方法&#xff1a;基于word2vec中的跳元模型&#xff0c;它将中心词表示为其子词向量之和。 字节对编码执行训练数据集的统计分析&#xff0c;以发现词内的公共符号。作为一种贪心方法&#xff0c;字节对编码迭代地合并最频繁的连续符号对。 子…

文献阅读:Finetuned Language Models Are Zero-Shot Learners

文献阅读&#xff1a;Finetuned Language Models Are Zero-Shot Learners 1. 文章简介2. 方法介绍3. 实验 1. 数据集整理2. 基础实验3. 消解实验 1. finetune任务数量2. 模型size3. Instruct Tuning4. Few-Shot5. Prompt Tuning 4. 结论 文献链接&#xff1a;https://arxiv.o…

简单理解小目标分割中的weighted BCE Loss与weighted IoU Loss

这两个损失函数出自《FNet: Fusion, Feedback and Focus for Salient Object Detection》一文中&#xff0c;用于处理显著性检测(二分割)中小目标的问题。对于传统的BCE Loss&#xff0c;其存在以下三个问题&#xff1a; 只是简单的将每个像素求BCE再平均&#xff0c;忽视了目…

day5——冒泡排序,选择排序和插入排序的学习

选择排序冒泡排序插入排序 选择排序 选择排序的基本思路就是&#xff1a; 首先假定第一个的下表为所有元素中最小的一个&#xff0c; 然后用后面的每一个元素跟这个元素进行比较&#xff0c; 如果后面的元素比这个元素更小一点&#xff0c; 那么就将找到的最小的元素的下标和…

【c++】vector实现(源码剖析+手画图解)

vector是我接触的第一个容器&#xff0c;好好对待&#xff0c;好好珍惜&#xff01; 目录 文章目录 前言 二、vector如何实现 二、vector的迭代器&#xff08;原生指针&#xff09; 三、vector的数据结构 图解&#xff1a; 四、vector的构造及内存管理 1.push_back() …

《爆肝整理》保姆级系列教程python接口自动化(十二)--https请求(SSL)(详解)

简介 本来最新的requests库V2.13.0是支持https请求的&#xff0c;但是一般写脚本时候&#xff0c;我们会用抓包工具fiddler&#xff0c;这时候会 报&#xff1a;requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590) 小编…

C++:提高篇: 栈-寄存器和函数状态:windows X86-64寄存器介绍

寄存器1、什么是寄存器2、寄存器分类3、windows X86寄存器命名规则4、寄存器相关术语5、寄存器分类5.1、RAX(accumulator register)5.2、RBX(Base register)5.3、RDX(Data register)5.4、RCX(counter register)5.5、RSI(Source index)5.6、RDI(Destination index)5.7、RSP(stac…

iptables和nftables的使用

文章目录前言iptable简介iptable命令使用iptables的四表五链nftables简介nftables命令的时候nftables与iptables的区别iptables-legacy和iptables-nft实例将指定protocol:ip:port的流量转发到本地指定端口前言 本文展示了&#xff0c;iptables和nftable命令的使用。 # 实验环…

win10 安装rabbitMQ详细步骤

win10 安装rabbitMQ详细步骤 win10 安装rabbitMQ详细步骤win10 安装rabbitMQ详细步骤一、下载安装程序二、安装配置erlang三、安装rabbitMQ四、验证初始可以通过用户名&#xff1a;guest 密码guest来登录。报错&#xff1a;安装RabbitMQ出现Plugin configuration unchanged.问题…

力扣SQL刷题10

目录标题618. 学生地理信息报告--完全不会的新题型1097. 游戏玩法分析 V - 重难点1127. 用户购买平台--难且不会618. 学生地理信息报告–完全不会的新题型 max()函数的功效&#xff1a;&#xff08;‘jack’, null, null&#xff09;中得出‘jack’&#xff0c;&#xff08;nul…

基于微信小程序图书馆座位预约管理系统

开发工具&#xff1a;IDEA、微信小程序服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8项目构建&#xff1a;maven数据库&#xff1a;mysql5.7前端技术&#xff1a;vue、uniapp服务端技术&#xff1a;springbootmybatis本系统分微信小程序和管理后台两部分&#xff0c;项目采用…

索引的基本介绍

索引概述-优缺点 索引介绍&#xff1a;索引是一种高效获取数据的数据结构&#xff1b; 索引优点&#xff1a;提供查询效率&#xff1b;降低IO成本&#xff1b;怎么减低IO成本呢&#xff1f;因为数据库的数据是存放在磁盘的&#xff0c;你要操作数据就会涉及到磁盘IO&#xff0…

Windows11 安装Apache24全过程

Windows11 安装Apache24全过程 一、准备工作 1、apache-httpd-2.4.55-win64-VS17.zip - 蓝奏云 2、Visual Studio Code-x64-1.45.1.exe - 蓝奏云 二、实际操作 1、将下载好的zip文件解压放到指定好的文件夹。我的是D:\App\PHP下 个人习惯把版本号带上。方便检测错误。 2…

数组常使用的方法

1. join (原数组不受影响)该方法可以将数组里的元素,通过指定的分隔符,以字符串的形式连接起来。返回值:返回一个新的字符串const arr[1,3,4,2,5]console.log(arr.join(-)&#xff1b;//1-3-4-2-52. push该方法可以在数组的最后面,添加一个或者多个元素结构: arr.push(值)返回值…

(考研湖科大教书匠计算机网络)第四章网络层-第一、二节:网络层概述及其提供的服务

获取pdf&#xff1a;密码7281专栏目录首页&#xff1a;【专栏必读】考研湖科大教书匠计算机网络笔记导航 文章目录一&#xff1a;网络层概述&#xff08;1&#xff09;概述&#xff08;2&#xff09;学习内容二&#xff1a;网络层提供的两种服务&#xff08;1&#xff09;面向连…

nginx越界读取缓存漏洞(CVE-2017-7529)

range格式: Range: <unit><range-start>- Range: <unit><range-start>-<range-end> Range: <unit><range-start>-<range-end>, <range-start>-<range-end> range事例&#xff1a; Range: bytes500-999 //表示第…