|
asbai
高级用户
积分 653
发帖 252
注册 2006-4-16
状态 离线
|
『第
46 楼』:
Quote: | Originally posted by jawbin at 2006-5-27 13:38:
我某些时候(例如,可能等同于 MS 的 GDI 堆的部分可能就会这样,此前我的时钟就是类似这样的,总之一些系统堆可能会这样处理以提高可能微乎其微 ... |
|
jawbin 兄很喜欢跟 MS 的 GDI 接口较劲啊,呵呵。其实打开 DC 的时候只不过是打开了一个句柄,实际的开销不过是 "++reference_count;" 之类的引用计数操作,通常没有什么内存分配的问题。
在栈中分配对象的大小跟最终生成的可执行程序尺寸没有任何关系。绝大部分编译器中,在栈中分配对象仅仅是修改一下相对于 ESP 的一个偏移值而已。不信的话你可以编译以下C代码:
int main(int argc, char* argv[])
{
unsigned char gbTEST[64*1024*1024]; // 在栈上分配64MB缓冲区
return 0;
}
看看编译出来的可执行程序会不会有64MB那么大。甚至,不光这个可执行程序会很小,运行时所消耗的内存甚至也不会超过几K,因为gbTEST只是在地址空间上保留了64MB的段落,由于没有真正的使用到它,所以分配给你的仅仅是进程虚地址空间中的一段而不是物理内存。
|
|
2006-5-27 16:37 |
|
|
jawbin
高级用户
积分 994
发帖 444
注册 2005-1-29
状态 离线
|
『第
47 楼』:
被 asbai 兄看穿了, 我是很看不惯 GDI
不过依据 MS 的说法, 它加速 DC 访问是用了 5 个 common DCs 中的一个用来缓存最近使用的 DC,而当这 5
个 DCs 不够的时候,就需要增加更多的 DCs 了. 至于别的小对象(笔,刷子等), 还不清楚, 可能也类似, 但是
问题应该与此相比小很多, 可以先不考虑. 当然 CS_OWNDC 也可以使窗体拥有自己的 DC, 但是, Windows 5.x
之前不被提倡, 估计是 Windows 5.x 之后系统本身对硬件资源的要求就高了, 所以可以"奢侈"一些了,无论如
何, DC 这个稍微有点庞大的东西总不能在资源紧张的系统上原样照搬. 每个窗体的 DC 的内容应该是不同的,
所以不可能引用吧. 即使如果某一个固定的窗口的 DC "相同", 也只需要获取一次(在窗体刚创建之后),最后销
毁一次, 不需要在频繁调用的 OnPaint 中开始来个 ++reference_count, 末尾来个 --reference_count 这样
的假动作吧?. 无论如何, 即使我不去"善意地"猜测它怎么在内部优化实现, 我还是对这样的代码很不舒服.
另外, asbai 兄的举例的确指出了我的错误, 应该是我疏忽了, 我指的是需要初始化的数据(由于使用数组初始
化数据很方便, 通常如果数据不需要初始化的话, 就可以用堆了)它不在栈上, 而是在附加段里. 不过这个小小
的例子有些微欠妥, 就是在栈上分配的太多, 在 VC 等可以编译 PE 文件的环境下编译可以通过, 但是运行会
出错. 而且, 显然, 在 TC 等可以编译 DOS 程序的环境下, 编译都不会通过的, 即使将内存模式设置为 HUGE.
|
|
2006-5-28 09:09 |
|
|
jawbin
高级用户
积分 994
发帖 444
注册 2005-1-29
状态 离线
|
『第
48 楼』:
所以, 除了零星的小东西, 我不会使用栈, 毕竟它还有点点宝贵, 否则, 递归是不用限制的.
不过 GDI 既然是 MS 这样的巨头搞出来的, 应该有它的道理或"苦衷", 而且它也在发展, 比如后来出现的 GDI+, 在 Vista 中可能更有大的发展. 但是显然, 能真正实用的 Windows 不运行在 8086 上.
[ Last edited by jawbin on 2006-5-28 at 09:18 ]
|
|
2006-5-28 09:13 |
|
|
zyl910
中级用户
积分 282
发帖 126
注册 2006-5-17
状态 离线
|
『第
49 楼』:
对于栈
Windows系统默认为每个线程预留(Reserve)2MB的空间
但最开始只分配(Commit)两页(8KB)
随着递归执行,线程可能越过分配的区域,会访问到保留的区域
这时Windows系统会自动处理该异常,将访问目标那片内存提交(Commit)
保留区域的最低8KB用于越界检查(报告栈溢出异常),不可使用
注意
在栈中定义变量只是修改esp指针,不会访问实际内存
只有访问栈中变量时才是访问内存
创建线程(CreateThread)时可决定该线程 栈的大小(dwStackSize)参数
在PE文件格式中有设置栈大小的字段(IMAGE_OPTIONAL_HEADER32的SizeOfStackReserve、SizeOfStackCommit)
Quote: | typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
//
// NT additional fields.
//
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; |
|
现在虚拟机的垃圾回收机制实际上是模拟栈操作(美其名曰“内存池”)
每次创建对象时,在内存池后面的空闲空间分配一段内存出来,再修改内存池空闲空间指针。即每次都在后面分配
当发现内存池空间不够时,执行垃圾回收算法,跟踪指针,标记空闲区域
为了减少内存碎片,将后面的内存挪动到前面来,补足空闲区域,并修正指针
所以垃圾回收机制占用内存大,且垃圾回收算法很复杂,为了减少碎片还得执行内存搬运,会影响程序性能
为什么现在流行Java和.Net
这是因为现在计算机行业的应用急剧扩展
很多人抱着幻想来学编程
只想简单学一下控件使用
根本没有算法功底,更不知内存管理算法为何物
(实际上垃圾回收算法只是一种高级的内存管理算法,你可以自己编写的)
而对于操作系统
不用内存管理算法简直是笑话(没有内存管理的操作系统还能叫操作系统吗)
所以GDI对象有自己的内存分配器的,效率很高
(其实经历过windows 3.0的人都知道,那时GDI堆是64KB的。如果不注意释放的话,很容易耗尽GDI资源)
现在想学内存管理算法的话
推荐看侯捷的《STL源码解析》(算法理论书籍估计现在没人愿意看了)
STL是很好一个范本
[ Last edited by zyl910 on 2006-5-28 at 10:09 ]
|
人类存在的目的就是试图理解人类为何存在 |
|
2006-5-28 10:05 |
|
|
zyl910
中级用户
积分 282
发帖 126
注册 2006-5-17
状态 离线
|
『第
50 楼』:
GDI+只是为适应现在的应用开发 而提出来的一个高级类库(GDI才是最根本的底层借口)
真正的图形图像处理函数都是自己《计算图形学》、《数字图像处理》算法写出来的
要不然你当GDI+的高级功能是怎么写出来的
图形程序员名言:只有能让我操作显存,我就能描绘整个世界
|
人类存在的目的就是试图理解人类为何存在 |
|
2006-5-28 10:08 |
|
|
jawbin
高级用户
积分 994
发帖 444
注册 2005-1-29
状态 离线
|
『第
51 楼』:
zyl910 兄也终于来了!
我并没有说 GDI+ 是平地起高楼, 呵呵, 一个高级的系统是有很多层的.
我只是喜欢看上去比较优美的接口, 当然首先它不是在追求低效.而一个发展的系统,总会让它自己越来越接近自己的理想,当逐步被减少硬件上的束缚之后.所以,一个系统越往后发展,就越值得借鉴.它会越来越成熟.但是理想总是无法达到的,否则它就该改名叫现实而不是叫理想了 *^_^*
所以, 即使在 Vista 已经发售(据说已经推迟了), 它其实还没达到预期目标,至少没达到我的预期目标 :), 但是毕竟让人看到希望:这条路走得还不错,可以继续前进.
[ Last edited by jawbin on 2006-5-28 at 13:55 ]
|
|
2006-5-28 13:44 |
|
|
asbai
高级用户
积分 653
发帖 252
注册 2006-4-16
状态 离线
|
『第
52 楼』:
Quote: | Originally posted by jawbin at 2006-5-28 09:09:
被 asbai 兄看穿了:P, 我是很看不惯 GDI
不过依据 MS 的说法, 它加速 DC 访问是用了 5 个 common DCs 中的一个用来缓存最近使用的 DC,而当这 5
个 DCs 不够 ... |
|
引用计数自然是在同一个窗口内的DC上使用的,每个DC有自己的 reference count,一般来说,这不会降低效率。
|
|
2006-5-28 13:46 |
|
|
jawbin
高级用户
积分 994
发帖 444
注册 2005-1-29
状态 离线
|
『第
53 楼』:
我不极力推崇底层, 因为那可以有点"无止境",最后可能追究到特定的 CPU 指令集是否最优秀了,那时候已经真正"远足"了,可以跑去设计 CPU 了.
对于一个特定追究的目标, 可以竭力去优化. 但是, 有时候复用也非常重要. 否则, 那时候出来的就不是一个通用的 intel 4004, 那目前的计算机世界是什么样子完全不可预料.
[ Last edited by jawbin on 2006-5-28 at 13:58 ]
|
|
2006-5-28 13:49 |
|
|
asbai
高级用户
积分 653
发帖 252
注册 2006-4-16
状态 离线
|
『第
54 楼』:
Quote: | Originally posted by zyl910 at 2006-5-28 10:05:
对于栈
Windows系统默认为每个线程预留(Reserve)2MB的空间
但最开始只分配(Commit)两页(8KB)
随着递归执行,线程可能越过分配的区域@... |
|
zyl910兄正解!
不过STL的allocator由于要考虑对象构造与析构的语义兼容,很多时候效率颇低。SGI STL的 Pool Allocator 效率尚可,但仍然有很大的优化空间。
例如:对没有构造、析构和拷贝构造问题的内置数据类型而言,用realloc的语义改变容器尺寸效率远高于创建新块;逐个拷贝旧块中的对象;释放旧块这个流程。
|
|
2006-5-28 13:53 |
|
|
jawbin
高级用户
积分 994
发帖 444
注册 2005-1-29
状态 离线
|
『第
55 楼』:
Quote: | Originally posted by asbai at 2006-5-28 01:46 PM:
引用计数自然是在同一个窗口内的DC上使用的,每个DC有自己的 reference count,一般来说,这不会降低效率。 |
|
按 MS 的说法, 应该是或者使用就近的 cache, 或者在 5 个 common DCs 中使用一个, 或者不够用的时候, 增加. 其实内部如何实现, 已经不是很重要了, 重要的是, 当我看到这样一些"矫情的"动作, 我就大倒胃口. 但是 MS 来说, 可能是"不得已", 或者说, "没什么大不了", 或者说, "没什么错". 它没有想运行在资源有限的系统上, 所以, 它完全不会遇到什么问题. 它通常面临的是 Windows 这个产品的用户的问题.
|
|
2006-5-28 13:54 |
|
|
asbai
高级用户
积分 653
发帖 252
注册 2006-4-16
状态 离线
|
『第
56 楼』:
另外,jawbin兄:
Win32为每个线程的默认保留栈空间是2MB,如果兄台将我的例子用在自己Create的一个Thread里试验,一定会有栈溢出错误。这个需要在Create的时候手动指定保留栈的尺寸。
但是Win32对每个进程的主线程是可以运行时动态调整栈空间尺寸的,应该不至于出现运行时错?
|
|
2006-5-28 13:59 |
|
|
asbai
高级用户
积分 653
发帖 252
注册 2006-4-16
状态 离线
|
『第
57 楼』:
Quote: | Originally posted by jawbin at 2006-5-28 13:54:
按 MS 的说法, 应该是或者使用就近的 cache, 或者在 5 个 common DCs 中使用一个, 或者不够用的时候, 增加. 其实内部如何实现, 已经不是很重要了, 重要皠... |
|
5个应该是初始值,超出以后引用计数仍然是有效的。另外,这5个貌似说的是memory dc,否是Window DC,呵呵。
这是典型的空间换时间的算法,就像 cpu 的L1/L2 cache、OS的磁盘访问缓冲等等。个人认为这确实是天经地义,不付出这点空间,换来的时间劣化是无法忍受的。
|
|
2006-5-28 14:04 |
|
|
jawbin
高级用户
积分 994
发帖 444
注册 2005-1-29
状态 离线
|
『第
58 楼』:
另外,我不是想设计操作系统(至少目前是这样,因为我还没有那个能力), 我所做的, 是基于操作系统之上的. 我前面已经说过, 如果从 BIOS 起做, 对我而言太困难了:)
而且目前我所做的, 也仅仅是我自己用, 可以不用担心第三方对内存的非预期访问. 呵呵. 当然, 对于一个 platform (Java 既然不是一个 OS, 那么就把这些 runtimes 都统称为 platforms 吧), 不管理内存, 它有什么资格成为一个 platform?
|
|
2006-5-28 14:08 |
|
|
jawbin
高级用户
积分 994
发帖 444
注册 2005-1-29
状态 离线
|
『第
59 楼』:
Quote: | Originally posted by asbai at 2006-5-28 01:59 PM:
另外,jawbin兄:
Win32为每个线程的默认保留栈空间是2MB,如果兄台将我的例子用在自己Create的一个Thread里试验,一定会有栈溢出错误。这个需要在Cr ... |
|
asbai 兄, these times, we've gone too far...
我们已经跑到"罪恶的" 640K 以外太远了, 我体力不支了
[ Last edited by jawbin on 2006-5-28 at 14:14 ]
|
|
2006-5-28 14:11 |
|
|
asbai
高级用户
积分 653
发帖 252
注册 2006-4-16
状态 离线
|
『第
60 楼』:
Quote: | Originally posted by jawbin at 2006-5-28 14:08:
另外,我不是想设计操作系统(至少目前是这样,因为我还没有那个能力), 我所做的, 是基于操作系统之上的. 我前面已经说过, 如果从 BIOS 起做, 对我而言 ... |
|
java之类属虚拟机范畴,也就是说,它是跑在一个平台(OS)之上的平台
虽然俺也B4 VM,不过高层利用底层提供的既有功能好像是说的过去。即使OS也要利用它的底层(硬件和BIOS)所提供的既有能力嘛,哪有空中楼阁啊?
例如:硬件提供了MMU,OS就应该充分利用起来,而不是用纯软件实现分页;硬件提供了DMA控制器,OS就应该尽量用它做IO,而不应该自己实行用CPU手工搬运数据的算法~
[ Last edited by asbai on 2006-5-28 at 14:19 ]
|
|
2006-5-28 14:14 |
|
|