Android内存管理机制详解 (zhuan)

http://www.2cto.com/kf/201212/175786.html

与windows内存区别
在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然。这是Linux内存管理的一个优秀特性,在这方面,区别于 Windows的内存管理。主要特点是,无论物理内存有多大,Linux都将其充份利用,将一些程序调用过的硬盘数据读入内存,利用内存读写的高速特性来提高Linux系统的数据访问性能。而Windows是只在需要内存时,才为应用程序分配内存,并不能充分利用大容量的内存空间。换句话说,每增加一些物理内存,Linux都将能充分利用起来,发挥了硬件投资带来的好处,而Windows只将其做为摆设,即使增加8GB甚至更大。

android内存的意义
其实我们在用安卓手机的时候不用太在意剩余内存,Android上的应用是java,当然需要虚拟机,而android上的应用是带有独立虚拟机的,也就是每开一个应用就会打开一个独立的虚拟机。其实和java的垃圾回收机制类似,系统有一个规则来回收内存。进行内存调度有个阀值,只有低于这个值系统才会按一个列表来关闭用户不需要的东西。当然这个值默认设置得很小,所以你会看到内存老在很少的数值徘徊。但事实上他并不影响速度。相反加快了下次启动应用的速度。这本来就是 android标榜的优势之一,如果人为去关闭进程,没有太大必要。特别是使用自动关进程的软件。为什么内存少的时候运行大型程序会慢呢,原因是:在内存剩余不多时打开大型程序时会触发系统自身的调进程调度策略,这是十分消耗系统资源的操作,特别是在一个程序频繁向系统申请内存的时候。这种情况下系统并不会关闭所有打开的进程,而是选择性关闭,频繁的调度自然会拖慢系统。

进程管理软件
进程管理软件有无必要呢?有的。就是在运行大型程序之前,你可以手动关闭一些进程释放内存,可以显著的提高运行速度。但一些小程序完全可交由系统自己管理。那么如果不关程序是不是会更耗电。android的应用在被切换到后台时,它其实已经被暂停了,并不会消耗cpu资源只保留了运行状态。所以为什么有的程序切出去重进会到主界面。但是一个程序如果想要在后台处理些东西,如音乐播放,它就会开启一个服务。服务可在后台持续运行,所以在后台耗电的也只有带服务的应用了。我们可以把带服务的进程用进程管理软件关闭就可以了。没有带服务的应用在后台是完全不耗电的没有必要关闭。这种设计本来就是一个非常好的设计,下次启动程序时会更快,因为不需要读取界面资源,何必要关掉他们抹杀这个android的优点呢。

Android进程种类
1. 前台进程(foreground)

目前正在屏幕上显示的进程和一些系统进程。举例来说,Dialer,Storage,Google Search等系统进程就是前台进程;再举例来说,当你运行一个程序,如浏览器,当浏览器界面在前台显示时,浏览器属于前台进程(foreground),但一旦你按home回到主界面,浏览器就变成了后台程序(background)。我们最不希望终止的进程就是前台进程。

2. 可见进程(visible)

可见进程是一些不再前台,但用户依然可见的进程,举个例来说:widget、输入法等,都属于visible。这部分进程虽然不在前台,但与我们的使用也密切相关,我们也不希望它们被终止(你肯定不希望时钟、天气,新闻等widget被终止,那它们将无法同步,你也不希望输入法被终止,否则你每次输入时都需要重新启动输入法)

3. 桌面进程(home app)

即launcher,保证在多任务切换之后,可以快速返回到home界面而不需重新加载launcher

4. 次要服务(secondary server)

目前正在运行的一些服务(主要服务,如拨号等,是不可能被进程管理终止的,故这里只谈次要服务),举例来说:谷歌企业套件,Gmail内部存储,联系人内部存储等。这部分服务虽然属于次要服务,但很一些系统功能依然息息相关,我们时常需要用到它们,所以也太希望他们被终止

5. 后台进程(hidden)

即是后台进程(background),就是我们通常意义上理解的启动后被切换到后台的进程,如浏览器,阅读器等。当程序显示在屏幕上时,他所运行的进程即为前台进程(foreground),一旦我们按home返回主界面(注意是按home,不是按back),程序就驻留在后台,成为后台进程(background)。后台进程的管理策略有多种:有较为积极的方式,一旦程序到达后台立即终止,这种方式会提高程序的运行速度,但无法加速程序的再次启动;也有较消极的方式,尽可能多的保留后台程序,虽然可能会影响到单个程序的运行速度,但在再次启动已启动的程序时,速度会有所提升。这里就需要用户根据自己的使用习惯找到一个平衡点

6. 内容供应节点(content provider)

没有程序实体,进提供内容供别的程序去用的,比如日历供应节点,邮件供应节点等。在终止进程时,这类程序应该有较高的优先权

7. 空进程(empty)

没有任何东西在内运行的进程,有些程序,比如BTE,在程序退出后,依然会在进程中驻留一个空进程,这个进程里没有任何数据在运行,作用往往是提高该程序下次的启动速度或者记录程序的一些历史信息。这部分进程无疑是应该最先终止的。

幽灵刽子手LMK (Low Memory Killer)

执行条件
剩余内存小于应用定义的APP_MEM值,开始查看adj值列表,kill相应程序。

实现机制
Low Memory Killer的源代码在kernel/drivers/staging/android/lowmemorykiller.c中

[cpp]
module_init(lowmem_init);

module_exit(lowmem_exit);

module_init(lowmem_init);

module_exit(lowmem_exit); 模块加载和退出的函数,主要的功能就是register_shrinker和unregister_shrinker结构体lowmem_shrinker。主要是将函数lowmem_shrink注册到shrinker链表里,在mm_scan调用。

下面详细的介绍这个函数:

[cpp]
for (i = 0; i < array_size; i++) {
if (other_file < lowmem_minfree[i]) {
min_adj = lowmem_adj[i];
break;
}
}

for (i = 0; i < array_size; i++) {
if (other_file < lowmem_minfree[i]) {
min_adj = lowmem_adj[i];
break;
}
}other_file, 系统的空闲内存数,根据上面的逻辑判断出,low memory killer需要对adj高于多少(min_adj)的进程进行分析是否释放。

[cpp]
if (nr_to_scan <= 0 || min_adj == OOM_ADJUST_MAX + 1) {
lowmem_print(5, "lowmem_shrink %d, %x, return %d\n",
nr_to_scan, gfp_mask, rem);
return rem;
}

if (nr_to_scan <= 0 || min_adj == OOM_ADJUST_MAX + 1) {
lowmem_print(5, "lowmem_shrink %d, %x, return %d\n",
nr_to_scan, gfp_mask, rem);
return rem;
} 判断,系统当前的状态是否需要进行low memory killer。

[cpp]
for_each_process(p) {
struct mm_struct *mm;
struct signal_struct *sig;
int oom_adj;
task_lock(p);
mm = p->mm;
sig = p->signal;
if (!mm || !sig) {
task_unlock(p);
continue;
}
oom_adj = sig->oom_adj;
if (oom_adj < min_adj) {
task_unlock(p);
continue;
}
tasksize = get_mm_rss(mm);
task_unlock(p);
if (tasksize <= 0)
continue;
if (selected) {
if (oom_adj < selected_oom_adj)
continue;
if (oom_adj == selected_oom_adj &&
tasksize <= selected_tasksize)
continue;
}
selected = p;
selected_tasksize = tasksize;
selected_oom_adj = oom_adj;
lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n",
p->pid, p->comm, oom_adj, tasksize);
}

for_each_process(p) {
struct mm_struct *mm;
struct signal_struct *sig;
int oom_adj;
task_lock(p);
mm = p->mm;
sig = p->signal;
if (!mm || !sig) {
task_unlock(p);
continue;
}
oom_adj = sig->oom_adj;
if (oom_adj < min_adj) {
task_unlock(p);
continue;
}
tasksize = get_mm_rss(mm);
task_unlock(p);
if (tasksize <= 0)
continue;
if (selected) {
if (oom_adj < selected_oom_adj)
continue;
if (oom_adj == selected_oom_adj &&
tasksize <= selected_tasksize)
continue;
}
selected = p;
selected_tasksize = tasksize;
selected_oom_adj = oom_adj;
lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n",
p->pid, p->comm, oom_adj, tasksize);
}对每个sig->oom_adj大于min_adj的进程,找到占用内存最大的进程存放在selected中。

[cpp]
if (selected) {
if (fatal_signal_pending(selected)) {
pr_warning("process %d is suffering a slow death\n",
selected->pid);
read_unlock(&tasklist_lock);
return rem;
}
lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n",
selected->pid, selected->comm,
selected_oom_adj, selected_tasksize);
force_sig(SIGKILL, selected);
rem -= selected_tasksize;
}

if (selected) {
if (fatal_signal_pending(selected)) {
pr_warning("process %d is suffering a slow death\n",
selected->pid);
read_unlock(&tasklist_lock);
return rem;
}
lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n",
selected->pid, selected->comm,
selected_oom_adj, selected_tasksize);
force_sig(SIGKILL, selected);
rem -= selected_tasksize;
}发送SIGKILL信息,杀掉该进程。

在了解了其机制和原理之后,我们发现它的实现非常简单,与标准的Linux OOM机制类似,只是实现方式稍有不同。标准Linux的OOM Killer机制在mm/oom_kill.c中实现,且会被__alloc_pages_may_oom调用(在分配内存时,即mm/page_alloc.c中)。oom_kill.c最主要的一个函数是out_of_memory,它选择一个bad进程Kill,Kill的方法同样是通过发送SIGKILL信号。在out_of_memory中通过调用select_bad_process来选择一个进程Kill,选择的依据在badness函数中实现,基于多个标准来给每个进程评分,评分最高的被选中并Kill。一般而言,占用内存越多,oom_adj就越大,也就越有可能被选中。

资源配置
阈值表可以通过/sys/module/lowmemorykiller/parameters/adj和/sys/module/lowmemorykiller/parameters/minfree进行配置,例如在init.rc中:

[plain]
# Write value must be consistent with the above properties.

write /sys/module/lowmemorykiller/parameters/adj 0,1,2,7,14,15
write /proc/sys/vm/overcommit_memory 1
write /sys/module/lowmemorykiller/parameters/minfree 1536,2048,4096,5120,5632,6144

class_start default

# Write value must be consistent with the above properties.

write /sys/module/lowmemorykiller/parameters/adj 0,1,2,7,14,15
write /proc/sys/vm/overcommit_memory 1
write /sys/module/lowmemorykiller/parameters/minfree 1536,2048,4096,5120,5632,6144

class_start default进程oom_adj同样可以进行设置,通过write /proc/<PID>/oom_adj ,在init.rc中,init进程的pid为1,omm_adj被配置为-16,永远不会被杀死。

[plain] view plaincopyprint?# Set init its forked children‘s oom_adj.

write /proc/1/oom_adj -16

# Set init its forked children‘s oom_adj.

write /proc/1/oom_adj -16 Low memory killer的基本原理我们应该弄清了,正如我前面所说的,进程omm_adj的大小跟进程的类型以及进程被调度的次序有关。进程的类型,可以在ActivityManagerService中清楚的看到:

[java]
static final int EMPTY_APP_ADJ;
static final int HIDDEN_APP_MAX_ADJ;
static final int HIDDEN_APP_MIN_ADJ;
static final int HOME_APP_ADJ;
static final int BACKUP_APP_ADJ;
static final int SECONDARY_SERVER_ADJ;
static final int HEAVY_WEIGHT_APP_ADJ;
static final int PERCEPTIBLE_APP_ADJ;
static final int VISIBLE_APP_ADJ;
static final int FOREGROUND_APP_ADJ;
static final int CORE_SERVER_ADJ = -12;
static final int SYSTEM_ADJ = -16;<SPAN style="FONT-FAMILY: Calibri; FONT-SIZE: 14px"></SPAN>

static final int EMPTY_APP_ADJ;
static final int HIDDEN_APP_MAX_ADJ;
static final int HIDDEN_APP_MIN_ADJ;
static final int HOME_APP_ADJ;
static final int BACKUP_APP_ADJ;
static final int SECONDARY_SERVER_ADJ;
static final int HEAVY_WEIGHT_APP_ADJ;
static final int PERCEPTIBLE_APP_ADJ;
static final int VISIBLE_APP_ADJ;
static final int FOREGROUND_APP_ADJ;
static final int CORE_SERVER_ADJ = -12;
static final int SYSTEM_ADJ = -16; ActivityManagerService定义各种进程的oom_adj,CORE_SERVER_ADJ代表一些核心的服务的omm_adj,数值为-12,由前面的分析可知道,这类进程永远也不会被杀死。

在init.rc中:

[plain]
# Define the oom_adj values for the classes of processes that can be
# killed by the kernel. These are used in ActivityManagerService.
setprop ro.FOREGROUND_APP_ADJ 0
setprop ro.VISIBLE_APP_ADJ 1
setprop ro.HOME_APP_ADJ 1
setprop ro.PERCEPTIBLE_APP_ADJ 2
setprop ro.HEAVY_WEIGHT_APP_ADJ 3
setprop ro.SECONDARY_SERVER_ADJ 4
setprop ro.BACKUP_APP_ADJ 5
setprop ro.HIDDEN_APP_MIN_ADJ 7
setprop ro.EMPTY_APP_ADJ 15

# Define the memory thresholds at which the above process classes will
# be killed. These numbers are in pages (4k).
setprop ro.FOREGROUND_APP_MEM 2048
setprop ro.VISIBLE_APP_MEM 3072
setprop ro.HOME_APP_MEM 3072
setprop ro.PERCEPTIBLE_APP_MEM 4096
setprop ro.HEAVY_WEIGHT_APP_MEM 4096
setprop ro.SECONDARY_SERVER_MEM 10240
setprop ro.BACKUP_APP_MEM 10240
setprop ro.HIDDEN_APP_MEM 10240
setprop ro.EMPTY_APP_MEM 14336

# Write value must be consistent with the above properties.
# Note that the driver only supports 6 slots, so we have combined some of
# the classes into the same memory level; the associated processes of higher
# classes will still be killed first.
write /sys/module/lowmemorykiller/parameters/adj 0,1,2,4,7,15

write /proc/sys/vm/overcommit_memory 1
write /proc/sys/vm/min_free_order_shift 4
write /sys/module/lowmemorykiller/parameters/minfree 2048,3072,4096,10240,10240,14336

# Set init its forked children‘s oom_adj.
write /proc/1/oom_adj -16

# Define the oom_adj values for the classes of processes that can be
# killed by the kernel. These are used in ActivityManagerService.
setprop ro.FOREGROUND_APP_ADJ 0
setprop ro.VISIBLE_APP_ADJ 1
setprop ro.HOME_APP_ADJ 1
setprop ro.PERCEPTIBLE_APP_ADJ 2
setprop ro.HEAVY_WEIGHT_APP_ADJ 3
setprop ro.SECONDARY_SERVER_ADJ 4
setprop ro.BACKUP_APP_ADJ 5
setprop ro.HIDDEN_APP_MIN_ADJ 7
setprop ro.EMPTY_APP_ADJ 15

# Define the memory thresholds at which the above process classes will
# be killed. These numbers are in pages (4k).
setprop ro.FOREGROUND_APP_MEM 2048
setprop ro.VISIBLE_APP_MEM 3072
setprop ro.HOME_APP_MEM 3072
setprop ro.PERCEPTIBLE_APP_MEM 4096
setprop ro.HEAVY_WEIGHT_APP_MEM 4096
setprop ro.SECONDARY_SERVER_MEM 10240
setprop ro.BACKUP_APP_MEM 10240
setprop ro.HIDDEN_APP_MEM 10240
setprop ro.EMPTY_APP_MEM 14336

# Write value must be consistent with the above properties.
# Note that the driver only supports 6 slots, so we have combined some of
# the classes into the same memory level; the associated processes of higher
# classes will still be killed first.
write /sys/module/lowmemorykiller/parameters/adj 0,1,2,4,7,15

write /proc/sys/vm/overcommit_memory 1
write /proc/sys/vm/min_free_order_shift 4
write /sys/module/lowmemorykiller/parameters/minfree 2048,3072,4096,10240,10240,14336

# Set init its forked children‘s oom_adj.
write /proc/1/oom_adj -16ActivityManagerService.java

打开程序或者有程序进入后台时都会执行updateOomAdjLocked()函数:

[java]
final boolean updateOomAdjLocked() {
boolean didOomAdj = true;
final ActivityRecord TOP_ACT = resumedAppLocked();
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;

if (false) {
RuntimeException e = new RuntimeException();
e.fillInStackTrace();
Slog.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
}

mAdjSeq++;

// Let‘s determine how many processes we have running vs.
// how many slots we have for background processes; we may want
// to put multiple processes in a slot of there are enough of
// them.
int numSlots = HIDDEN_APP_MAX_ADJ - HIDDEN_APP_MIN_ADJ + 1;
int factor = (mLruProcesses.size()-4)/numSlots;
if (factor < 1) factor = 1;
int step = 0;
int numHidden = 0;

// First try updating the OOM adjustment for each of the
// application processes based on their current state.
int i = mLruProcesses.size();
int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
while (i > 0) {
i--;
ProcessRecord app = mLruProcesses.get(i);
//Slog.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
if (curHiddenAdj < EMPTY_APP_ADJ
&& app.curAdj == curHiddenAdj) {
step++;
if (step >= factor) {
step = 0;
curHiddenAdj++;
}
}
if (app.curAdj >= HIDDEN_APP_MIN_ADJ) {
if (!app.killedBackground) {
numHidden++;
if (numHidden > MAX_HIDDEN_APPS) {
Slog.e(TAG, "No longer want " + app.processName
+ " (pid " + app.pid + "): hidden #" + numHidden);
EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
app.processName, app.setAdj, "too many background");
app.killedBackground = true;
Process.killProcessQuiet(app.pid);
}
}
}
} else {
didOomAdj = false;
}
}
// If we return false, we will fall back on killing processes to
// have a fixed limit. Do this if a limit has been requested; else
// only return false if one of the adjustments failed.
return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
}<SPAN style="FONT-FAMILY: Calibri; FONT-SIZE: 14px"> </SPAN>

final boolean updateOomAdjLocked() {
boolean didOomAdj = true;
final ActivityRecord TOP_ACT = resumedAppLocked();
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;

if (false) {
RuntimeException e = new RuntimeException();
e.fillInStackTrace();
Slog.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
}

mAdjSeq++;

// Let‘s determine how many processes we have running vs.
// how many slots we have for background processes; we may want
// to put multiple processes in a slot of there are enough of
// them.
int numSlots = HIDDEN_APP_MAX_ADJ - HIDDEN_APP_MIN_ADJ + 1;
int factor = (mLruProcesses.size()-4)/numSlots;
if (factor < 1) factor = 1;
int step = 0;
int numHidden = 0;

// First try updating the OOM adjustment for each of the
// application processes based on their current state.
int i = mLruProcesses.size();
int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
while (i > 0) {
i--;
ProcessRecord app = mLruProcesses.get(i);
//Slog.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
if (curHiddenAdj < EMPTY_APP_ADJ
&& app.curAdj == curHiddenAdj) {
step++;
if (step >= factor) {
step = 0;
curHiddenAdj++;
}
}
if (app.curAdj >= HIDDEN_APP_MIN_ADJ) {
if (!app.killedBackground) {
numHidden++;
if (numHidden > MAX_HIDDEN_APPS) {
Slog.e(TAG, "No longer want " + app.processName
+ " (pid " + app.pid + "): hidden #" + numHidden);
EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
app.processName, app.setAdj, "too many background");
app.killedBackground = true;
Process.killProcessQuiet(app.pid);
}
}
}
} else {
didOomAdj = false;
}
}
// If we return false, we will fall back on killing processes to
// have a fixed limit. Do this if a limit has been requested; else
// only return false if one of the adjustments failed.
return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
} 以上就是android内存管理机制的内容了,在一些设备内存比较低的情况下,我们可以对其内存进行优化,从而让我们的设备运行的更加流畅。

Android内存管理机制详解 (zhuan)

时间: 2024-12-19 23:01:16

Android内存管理机制详解 (zhuan)的相关文章

Android 内存管理机制详解

??嵌入式设备的一个普遍特点是内存容量相对有限.当运行的程序超过一定数量时,或者涉及复杂的计算时,很可能出现内存不足,进而导致系统卡顿的现象.Android 系统也不例外,它同样面临着设备物理内存短缺的困境.对于已经启动过一次的Android程序,再一次启动所花的时间会明显减少.原因在于Android系统并不马上清理那些已经"淡出视野"的程序(比如你调用Activity.finish退出UI界面).它们在一定的时间里仍然驻留在内存中.这样做的好处是明显的,即下一次启动不需要再为程序重新

memcached内存管理机制详解

    我们知道,memcached是一个内存缓存系统,因此对于内存的管理是需要使用者了解的.本文将对memcached的内存模型及管理机制做一个详细的描述. 基本概念 在开始之前,有必要先了解几个基本概念: 1.slab class:在memcached中,对元素的管理是以slab为单元进行管理的.每个slab class对应一个或多个空间大小相同的chunk.参考下图一. 2.chunk:存放元素的最小单元.用户数据item(key.value等)最终会保存在chunk中.memcach

ARC内存管理机制详解

ARC在OC里面个人感觉又是一个高大上的牛词,在前面Objective-C中的内存管理部分提到了ARC内存管理机制,ARC是Automatic Reference Counting---自动引用计数.有自动引用计数,那么就得有手动引用计数MRC(Mannul Reference Counting),前面已经提到过了MRC.那么在ARC模式下是不是意味着我们就可以一点也不用进行内存管理的呢?并不是这样的,我们还需要代码进行内存的管理.下面会结合着代码把OC中的ARC机制做一个详细的总结(欢迎大家批

Android事件分发机制详解(1)----探究View的事件分发

探究View的事件分发 在Activity中,只有一个按钮,注册一个点击事件 [java] view plaincopy button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Log.d("TAG", "onClick execute"); } }); 如果在需要一个触摸事件 [java] view plaincopy button.setO

Android事件分发机制详解(2)----分析ViewGruop的事件分发

首先,我们需要 知道什么是ViewGroup,它和普通的View有什么区别? ViewGroup就是一组View的集合,它包含很多子View和ViewGroup,是Android 所有布局的父类或间接父类. 但ViewGroup也是一个View,只不过比起View,它可以包含子View和定义布局参数的功能. 现在,通过一个Demo演示Android中ViewGroup的事件分发机制. 首先我们来自定义一个布局,命名为MyLayout,继承自LinearLayout,如下 所示: public c

Android事件传递机制详解及最新源码分析——ViewGroup篇

在上一篇<Android事件传递机制详解及最新源码分析--View篇>中,详细讲解了View事件的传递机制,没掌握或者掌握不扎实的小伙伴,强烈建议先阅读上一篇. 好了,废话还是少说,直奔主题,开始本篇的ViewGroup事件传递机制探索之旅. 依然从简单的Demo例子现象开始分析 新建安卓工程,首先自定义一个Button以及一个RelativeLayout,很简单,只是重写了主要与事件传递机制相关的方法,代码如下: 自定义WLButton类: 1 public class WLButton e

Android 接口回调机制详解

在使用接口回调的时候发现了一个经常犯的错误,就是回调函数里面的实现有可能是用多线程或者是异步任务去做的,这就会导致我们期望函数回调完毕去返回一个主函数的结果,实际发现是行不通的,因为如果回调是多线程的话你是无法和主函数同步的,也就是返回的数据是错误的,这是非常隐秘的一个错误.那有什么好的方法去实现数据的线性传递呢?先介绍下回调机制原理. 回调函数 回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数

SAP 内存管理参数详解

ST02,这里是内存管理参数详解 初学SAP看到很内存管理参数会有一头雾水,不知如何解读,这里之接上货 这只是一个例子,实际设中,我们会通常直接设定以下: rdisp/roll_maxfs=125000 rdisp/roll_shm=125000 rdisp/PG_shm=312500 rdisp/PG_maxfs=312500 原文地址:https://www.cnblogs.com/tingxin/p/11958011.html

Android内存管理机制及优化

1.基于Linux内存管理 Android系统是基于Linux 2.6内核开发的开源操作系统,而linux系统的内存管理有其独特的动态存储管理机制.不过Android系统对Linux的内存管理机制进行了优化,Linux系统会在进程活动停止后就结束该进程,而Android把这些进程都保留在内存中,直到系统需要更多内存为止.这些保留在内存中的进程通常情况下不会影响整体系统的运行速度,并且当用户再次激活这些进程时,提升了进程的启动速度. 2.Android内存分配机制 与java的垃圾回收机制类似,系