2009/8/20 sagasw <sag...@gmail.com>:
好像和时间有关系,能不能先去掉timer看看?
> 有些内存持续增长问题无法被leak检测工具检测出来,比如你写个LRU,但是你忘了清掉老的失效的cache,那么代码本身没有什么泄露,只是因为逻辑写错了,没有进行清除而已。
>
一般来说,堆内存问题应该都会有提示。
>
OT一下,LZ的名字我看成了Jigsaw...
--
ghosTM55
Shanghai Linux User Group
Keep It Simple Stupid
http://ghosTunix.org 没有备案被机房和谐了 ;-(
9月份再上线 谢谢关注
Windbg里的adplus可以生成dump,不知是不是这个意思。
遇到一个问题,有些进入死胡同,跑来求救。
场景如下:
一个windows的mfc程序会一直运行(里面有timer),但是运行时大约每秒有4k的内存增长,非常稳定。问题是如果一直跑的话,程序的堆栈一定会被耗光。
想知道怎么能判断这4k内存是从哪个对象来的?使用过以下判断方式:
使用过·CRT的memory leak检查,但是没有找到问题,而且也不像是动态申请的内存,倒像是某个栈上的对象,现象是只要一拖动窗口或者做个最大最小化,内存都会急剧降低。
想用boundchecker,可应用太庞大,根本启动不起来。
试过PDH相关函数,也没有用。
不知道大家对于此类问题有什么办法?
On 8月21日, 上午9时39分, up duan <fixo...@gmail.com> wrote:
> 2009/8/21 up duan <fixo...@gmail.com>
>
>
>
>
>
>
>
> > 2009/8/20 sagasw <sag...@gmail.com>
>
> >> 遇到一个问题,有些进入死胡同,跑来求救。
>
> >> 场景如下:
>
> >> 一个windows的mfc程序会一直运行(里面有timer),但是运行时大约每秒有4k的内存增长,非常稳定。问题是如果一直跑的话,程序的堆栈一定会被耗-光。
>
> > 不应该是栈上的空间。如果是,你的程序应该没有办法正常调用函数和返回。
>
> >> 想知道怎么能判断这4k内存是从哪个对象来的?使用过以下判断方式:
>
> >> 使用过·CRT的memory
> >> leak检查,但是没有找到问题,而且也不像是动态申请的内存,倒像是某个栈上的对象,现象是只要一拖动窗口或者做个最大最小化,内存都会急剧降低。
>
> > 根据"稳定时4K、4K的消耗,窗口拖动或者最大最小化是内存剧烈消耗"可以大致看出是Windows的窗口系统在消耗内存。4K、4K的进行其实是因为Mem-ory
> > Page的大小是4K。也就是说,你的程序不是4K4K的申请,而是比4K小,累积一段实现显示为4K消耗。
>
> >> 想用boundchecker,可应用太庞大,根本启动不起来。
>
> >> 试过PDH相关函数,也没有用。
>
> >> 不知道大家对于此类问题有什么办法?
>
> > 一般没有什么通用的办法。MFC的嵌入式平台下的版本有内存泄露,较低版本VC6[没有SP4以前]以及以前的版本也有这个问题。
>
> 比如:
> CDC* dc = GetDC();
> ReleaseDC(dc);
> 这样在MFC的某些版本下就有内存泄露。- 隐藏被引用文字 -
>
> - 显示引用的文字 -
为什么多线程下CString就极易内存泄露。
2009/8/21 jinhu wang <wangji...@gmail.com>为什么多线程下CString就极易内存泄露。
MFC老版本的CString实现采用RefCount + COW,但是没有用Lock,所以多线程竞态条件经常导致起RefCount失效。
sagasw 写道:
你意思是多个线程公用一个CString变量还是共用CString类?
遇到一个问题,有些进入死胡同,跑来求救。
场景如下:
一个windows的mfc程序会一直运行(里面有timer),但是运行时大约每秒有4k的内存增长,非常稳定。问题是如果一直跑的话,程序的堆栈一定会被耗光。
a是临街资源,你当然要自己保护了
是的!即便是int也要保护。这是多线程编程的基础
为什么赋值操作不是原子的?
> a是临街资源,你当然要自己保护了
说得是轻松,
如果任何临界资源都保护得好好的,任何要注意的地方都处理得妥妥当当,这个世界就没那么多BUG了。
up duan的意思很明白,就是说容易不小心忽略了CString 的COW特性。
On 8月24日, 上午10时10分, jinhu wang <wangjinhu...@gmail.com> wrote:
> c语言中不知道哪个操作是原子操作。
> 至少我确认赋值操作不是。
> 而c++中。。。
>
> 2009/8/24 up duan <fixo...@gmail.com>
>
>
>
>
>
> > 2009/8/22 jinhu wang <wangjinhu...@gmail.com>
我想说别人说话可能不是十分严谨,能明白人家的意思就成。
up duan意思是说,int 的值复制通常是线程安全的,而CString 则比较危险。这有什么难理解的吗?
On 8月24日, 下午1时09分, Tiny fool <tinyf...@gmail.com> wrote:
> 赋值操作经常不是原子的,这不取决于语言,关键在于cpu是不是可以通过一个指令完成一个赋值操作。你看下 a=b;的汇编结果就知道了。
> 在多线程的情况下,你不好好考虑临界资源,当然会出问题,而且往往不会是小问题。
>
> 2009/8/24 hyifeng <hyif...@gmail.com>
往内存中写一个立即数就可以一条指令完成。所以"确认赋值操作不是" 这句话就不对。
2009/8/24 jinhu wang <wangji...@gmail.com>:
--
Any complex technology which doesn’t come with documentation must be the best
available.
Sent from Sydney, Nsw, Australia
COW 是 Copy on write 缩写。
而 "对int变量赋值是原子操作吗",我对你那句话的纠正如果存在谬误,请指教。
> CString比较危险这句话说的很不靠谱,很容易误导初学者。
> 我的意思是,任何一个全局变量,如果存在多线程访问,都是"比较危险"的!
我认为最危险的事就是,你认为自己做得足够安全却其实不是这样。
On 8月24日, 下午1时32分, jinhu wang <wangjinhu...@gmail.com> wrote:
> 我们可能都理解up duan的意思,只是想纠正他的理解偏差。
> CString比较危险这句话说的很不靠谱,很容易误导初学者。
> 我的意思是,任何一个全局变量,如果存在多线程访问,都是"比较危险"的!
>
> //我想说别人说话可能不是十分严谨,能明白人家的意思就成。
> //up duan意思是说,int 的值复制通常是线程安全的,而CString 则比较危险。这有什么难理解的吗?
> 2009/8/24 hyifeng <hyif...@gmail.com>
你的第二句陈述是完全正确的。
在实模式下是原子的,在保护模式下仍然是具有原子性的。比如,
MOV a,EAX
缺页异常是不可能EAX低16和高16位拷贝中间发生的。
所以即使系统有分页机制不会影响它的原子性的。
On 8月24日, 下午3时22分, jinhu wang <wangjinhu...@gmail.com> wrote:
> 不过你和up duan的问题还是很有意思的,因为我一下找不出反例来证明赋值语句不是原子操作。
> 在下面这个blog里有vc示例证明++操作不是原子的http://blog.joycode.com/peon/archive/2007/04/03/100308.joy
> 刚才我突然又想起loki库里有对原子操作的封装,loki对赋值原子操作的封装。
> 以下是loki在win环境下对赋值原子操作的封装:
> static void AtomicAssign(IntType& lval, volatile IntType& val)
> { InterlockedExchange(&lval, val); }
> 2009/8/24 hyifeng <hyif...@gmail.com>
>
>
>
> > 偏离了主题了。
> > 相比斗口舌,我对楼主如这个问题更感兴趣。
movl a, %eax
movl %eax, b
ldr r3, .L2 #取a的地址,放在r3
ldr r2, [r3, #0] #[]操作取r3地址里的值,放在r2
ldr r3, .L2+4 #取b的地址,放在r3
str r2, [r3, #0] #赋值
...
L2:
.word a
.word b
我可惜的是偏离主题太远了,因为别人口述上的一点瑕疵就开始跑题,其实他要传递的内容大家都心里都明白。
比如CPU1往地址a写了一个数,CPU2读的时候还是读到原来的值。
这时,需要用memory barrier来强制刷新。比如Intel x86的 lfence/sfence/mfence 指令。
另外,如果地址a不是充分对齐的(比如*a是32-bit,但是地址a是奇数),即便是一条写入指令,那也有可能分成两个机器周期来完成。这时,从另一
个CPU看,数据是不完整的。
volatile的三种用途:
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2006/n2016.html
Java 5的volatile倒是很强大,Java不愧是支持concurrent programming最强的主流语言。
On Aug 24, 2:07 pm, jinhu wang <wangjinhu...@gmail.com> wrote:
> 前面tiny和xiaojia le已经给了你足够的提示了吧!
> 我确信:对int变量赋值不是原子操作。如Tiny所言:关键在于cpu是不是可以通过一个指令完成一个赋值操作。
> 如果多线程环境下有一个int型全局变量i。
>
> - 按照我的理解,我肯定会用操作系统提供的同步原语对他进行保护。而且会尽量用volatile修饰这个变量。
>
> 你的第二句陈述是完全正确的。
>
> 2009/8/24 hyifeng <hyif...@gmail.com>
如果我没搞错,应该不会发生这种情况。
当cache刷到内存的时候是锁总线的,另一个cpu没办法读到半成品。
Shuo Chen说的多CPU的确是个麻烦的问题,有那位懂这些的能介绍一下。
看了一点零散的资料,还没有弄清楚cache和内存同步的行为是怎样的,
各个CPU有独立的 cache会怎样,共享cache又会怎样。
Shuo Chen说的多CPU的确是个麻烦的问题,有那位懂这些的能介绍一下。
CPU cache 以 cache line 为单位,一般是 32 或 64 bytes。
一条读存储的机器指令如果内存地址不对齐,则需要 2个总线周期或以上。
在cache中情况一样,而且读取的内存块可能在cache line 边界上(跨cache line)。
当cache line 被修改就会被标记为dirty,其他core对应的cache line 被标记为invalid。
这时若其他core要访问这个数据就会导致cache同步。
如果一个32bit数据刚好被分在两个cache line边界上,就可能会发生CPU-A只更新了其中一个cache-line 就被CPU-B拿去
用,导致一致性的问题。
若仅仅是内存位置不对齐,可能也是类似原因导致一致性问题。
SMP多线程下很多无法在一个总线周期内完成的指令都有可能出问题,例如ADD、XCHG,如果要保证它的原子性要加上LOCK前缀。
最简单的方式就是给共享资源都加上锁,一了百了。
Intel的手册说:
8.1.1 Guaranteed Atomic Operations
The Intel486 processor (and newer processors since) guarantees that
the following basic memory operations will always be carried out
atomically:
*Reading or writing a byte
*Reading or writing a word aligned on a 16-bit boundary
*Reading or writing a doubleword aligned on a 32-bit boundary
The Pentium processor (and newer processors since) guarantees that the
following additional memory operations will always be carried out
atomically:
*Reading or writing a quadword aligned on a 64-bit boundary
*16-bit accesses to uncached memory locations that fit within a 32-bit
data bus
The P6 family processors (and newer processors since) guarantee that
the following additional memory operation will always be carried out
atomically:
*Unaligned 16-, 32-, and 64-bit accesses to cached memory that fit
within a cache line
Accesses to cacheable memory that are split across bus widths, cache
lines, and page boundaries are not guaranteed to be atomic by the
Intel Core 2 Duo, Intel Atom, Intel Core Duo, Pentium M, Pentium 4,
Intel Xeon, P6 family, Pentium, and Intel486 processors. The Intel
Core 2 Duo, Intel Atom, Intel Core Duo, Pentium M, Pentium 4, Intel
Xeon, and P6 family processors provide bus control signals that permit
external memory subsystems to make split accesses atomic; however,
nonaligned data accesses will seriously impact the performance of the
processor and should be avoided.
多长期?一周重启一次行不行?真要是长期运行,程序一开始就不能这么写。
techabc 写道:
> 长期:一周肯定是不行的,最少也得三五个月
> 确实是C++,MFC,开始时候未作防碎片处理
> 这么说是真的无解了?
>
> 2009/8/25 Shuo Chen <gian...@gmail.com <mailto:gian...@gmail.com>>
>
> Java ? C++ ?
> 要是C++,恭喜你了,没辙。
> 整理内存碎片,要搬移某个地址的数据到另一个地址,那就要知道所有指向
> 这块地址的指针,这在C/C++里是无解的。
>
> 多长期?一周重启一次行不行?真要是长期运行,程序一开始就不能这么写。
>
> On Aug 25, 4:41 pm, techabc <tech...@gmail.com
On Aug 26, 2:18 pm, techabc <tech...@gmail.com> wrote:
> 系统搭建的时候没这根弦,所以......btw,Windows、*nix下的那些C、C++写的服务程序,都需要单独考虑内存分配机制吗?
>
> 2009/8/26 sagasw <sag...@gmail.com>
>
> > 这么长期运行的项目,也许应该搭配独立的内存分配模块,自己控制这些分配逻辑。
>
> > 2009/8/26 techabc <tech...@gmail.com>
>
> > 长期:一周肯定是不行的,最少也得三五个月 确实是C++,MFC,开始时候未作防碎片处理
> >> 这么说是真的无解了?
>
> >> 2009/8/25 Shuo Chen <giantc...@gmail.com>
On Aug 26, 9:52 am, techabc <tech...@gmail.com> wrote:
> 长期:一周肯定是不行的,最少也得三五个月确实是C++,MFC,开始时候未作防碎片处理
> 这么说是真的无解了?
>
> 2009/8/25 Shuo Chen <giantc...@gmail.com>
1, check handle leak.
Use Lua script to search the codes.
2, check memory leak.
If you use CRT, you could use:
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
//_CrtSetBreakAlloc(182366);
// http://msdn.microsoft.com/en-US/library/e5ewb1h3(VS.80).aspx
3, get performance data.
We could use PDH functions. CPDHData
4, 注释代码隔离问题。
5,
1. 加一个对象计数器, 哪种对象一直增加, 就是它了.
2. 申请比较多的类, 轮流内部增加一个 char buffer[65536], 看看内存增加是否加快, 很快就可以找出了.
6, VLD boundchecker ADPlus WinDbg SysInternals-Tools (handle)
7, OANOCACHE=1
http://msdn.microsoft.com/en-us/library/ms221105.aspx
For example, if the application allocates a BSTR and frees it, the free
block of memory is put into the BSTR cache by Automation. If the
application then allocates another BSTR, it can get the free block from
the cache. If the second BSTR allocation is not freed, IMallocSpy will
attribute the leak to the first allocation of the BSTR. You can
determine the correct source of the leak (the second allocation) by
disabling the BSTR caching using the debug version of Oleaut32.dll, and
by setting the environment variable OANOCACHE=1 before running the
application.
8, some tools Mozilla uses:
http://www.mozilla.org/performance/tools.html
9, 启用或禁用内存诊断可以调用全局函数 AfxEnableMemoryTracking()
#ifdef _DEBUG
CMemoryState oldMemState, newMemState, diffMemState;
oldMemState.Checkpoint();
#endif
…
(被测试的代码)
…
#ifdef _DEBUG
newMemState.Checkpoint();
if(diffMemState.Difference(oldMemState, newMemState)) {
TRACE(“Memory Leaked Here:\n\n” );
}
#endif
抄袭了toplanguage讨论中的一些想法。
http://groups.google.com/group/pongba/browse_thread/thread/6c871ba9a79be74a#
注意即使这种情况也不是atomic的
//global volatile int something_done;
do_something();
something_done = 1; // it's not atomic actually. it may be set earlier
than you think.
因为这里涉及smp, cache, 流水线的优化.
可以看这里的9页纸http://lwn.net/Articles/250967/
<What every programmer should know about memory>
没有一个32位的内存的变量是独立的吧(如是,就可以把这个变量删除),
如果你使用了 some_int = value这种最低层的atomic, 你必须在代码的很多地方使用很多内存屏障语句来保证运行的正确性.
linux 内核提供完整的atomic api和 内存屏障 api 做这些事情.
用户空间的库不知道有没有.
所以最好是加锁. 锁阻止了一切对多cpu多线程访问的有害优化, 也考虑了各种的污垢.
Google vld.h,程序退出会在output窗口打印memory leak
在 2009 年 8 20 日,9:54 下午,"sagasw" <sag...@gmail.com>编写:
遇到一个问题,有些进入死胡同,跑来求救。
场景如下:
一个windows的mfc程序会一直运行(里面有timer),但是运行时大约每秒有4k的内存增长,非常稳定。问题是如果一直跑的话,程序的堆栈一定会被耗光。
想知道怎么能判断这4k内存是从哪个对象来的?使用过以下判断方式:
使用过·CRT的memory leak检查,但是没有找到问题,而且也不像是动态申请的内存,倒像是某个栈上的对象,现象是只要一拖动窗口或者做个最大最小化,内存都会急剧降低。
想用boundchecker,可应用太庞大,根本启动不起来。
试过PDH相关函数,也没有用。
不知道大家对于此类问题有什么办法?
伪代码如下:
global int a = 0;
thread A
{
while (true)
{
a = MAX_INT;
}
}
thread B
{
while(true)
{
a = 0;
}
}
thread C
{
int x = a;
if (x != 0 && x != MAX_INT)
{
assert(false);
}
}
你可以写个小程序运行上面的伪代码。如果给int赋值不是原子操作,则a必定会出现0和1混合的例如0x00FF之类的赋值,则必定assert
(false)。
> > > > > > > > > ps:这个线索我不回复了。- 隐藏被引用文字 -
>
> - 显示引用的文字 -