今天碰到一个奇怪的问题,在一个php脚本中写了一个foreache循环,遍历一个数组,同时修改数组里面的元素。大致就是这样:
foreach ($a as $key => &$value) {
$value['ttt'] = '123';
}
forearch ($a as $key => $value) {
}
结果第二次循环的时候,数组最后一行数据居然没有了。
第一次循环完dump出来的数组又是对的,但是其中一行有点奇怪,大概是这样:
&array(1) {
[0]=>
&array(20) {
["sampleID"]=>'aaa'
}
}
和这个有没有关系呢?搜了一圈,找到原因了。
这篇解释得很清楚:
php foreach reference
解决方法就是在使用引用完后要unset一下。php manual也有说明
php:foreach
2016年3月31日星期四
2016年2月23日星期二
“Illegal double … value found during parsing” 错误
刚刚碰到的一个问题,数据提交时报"Illegal double '20160221E0259700' value found during parsing"错误。但是程序运行了一段时间,怎么会报错呢?查了一下,带"E"的串会被PHP认为是double变量,而要更新的这个字段是一个varchar类型,所以导致错误。
之前为啥没报错呢,因为代码太搓:update strid=2016123456,这样就没报错,实际上应该是update strrid='201612345'。坑啊!
之前为啥没报错呢,因为代码太搓:update strid=2016123456,这样就没报错,实际上应该是update strrid='201612345'。坑啊!
2016年1月15日星期五
GCC 4.4.6 const char* to char* compiler error
今天在编译一个同事的代码发现一个小问题,就是报编译错误: error: invalid conversion from ‘const char*’ to ‘char*’,报错出在strstr这个函数,但是他原来编译又是ok的。猜测是GCC版本不一致导致的问题,一看果然是,他用的gcc 4.1.2,我用的gcc 4.4.6。但是为啥gcc 4.4.6编译会报错呢,查了一下gcc 手册:
The table below shows the functions and files that have been changed.
An example.
链接:https://gcc.gnu.org/gcc-4.4/porting_to.html
=====
原来是C++的标准库头文件有变化,目标是“improving const-correctness”,其中就有strstr这个函数。好吧,在原来的代码修改了加了强制转化就ok了。
Strict null-terminated sequence utilities
Some of the standard C++ library include files have been edited to use replacement overloads for some common C library functions (if available), with the goal of improving const-correctness: functions passed aconst char*
return const char*
.The table below shows the functions and files that have been changed.
Header | Functions |
---|---|
<cstring> | strchr , strpbrk , strrchr , strstr , memchr |
<cwchar> | wcschr wcspbrk , wcsrchr , wcsstr , wmemchr |
#include <cstring> const char* str1; char* str2 = strchr(str1, 'a');Gives the following compiler error:
error: invalid conversion from ‘const char*’ to ‘char*’Fixing this is easy, as demonstrated below.
#include <cstring> const char* str1; const char* str2 = strchr(str1, 'a');More information about the C++ standard requirements can be found in chapter 21, section "Null-terminated sequence utilities."
链接:https://gcc.gnu.org/gcc-4.4/porting_to.html
=====
原来是C++的标准库头文件有变化,目标是“improving const-correctness”,其中就有strstr这个函数。好吧,在原来的代码修改了加了强制转化就ok了。
2015年6月9日星期二
linux OOM
最近碰到的一个问题:进程A先启动,运行正常,然后进程B启动,系统一下卡住了,过了一会,进程B启动完成,进行A却退出了。对这个现象百思不得其解啊。gdb调了一会,发现进程B在分配内存的时候(要分配的内存很大),会导致系统卡住,然后进程A退出。网上搜了一下,发现是linux OOM机制导致的这种问题。
简而言之:
1.当一个进程向linux请求内存分配时(不论是new或者malloc),linux通常会直接返回成功,实际上并未分配内存。
2.实际分配内存的时候,linux若发现系统内存不够,则可能执行OOM(根据系统配置决定)把其他进程kill掉(发送SIGTERM信号)
3.程序中对new或者malloc的分配是否成功的判断有时候是没用的。只有通过监控系统内存来判断程序的内存的使用是否有问题。
内核关于OOM的文章:
https://www.kernel.org/doc/gorman/html/understand/understand016.html
另外以下这篇文章对OOM分析比较到位:
http://blog.csdn.net/guomsh/article/details/6536915
简而言之:
1.当一个进程向linux请求内存分配时(不论是new或者malloc),linux通常会直接返回成功,实际上并未分配内存。
2.实际分配内存的时候,linux若发现系统内存不够,则可能执行OOM(根据系统配置决定)把其他进程kill掉(发送SIGTERM信号)
3.程序中对new或者malloc的分配是否成功的判断有时候是没用的。只有通过监控系统内存来判断程序的内存的使用是否有问题。
内核关于OOM的文章:
https://www.kernel.org/doc/gorman/html/understand/understand016.html
另外以下这篇文章对OOM分析比较到位:
http://blog.csdn.net/guomsh/article/details/6536915
Linux Out-of-Memory(OOM) Killer
Linux有一个特性:OOM Killer,一个保护机制,用于避免在内存不足的时候不至于出现严重问题,把一些无关的进程优先杀掉,即在内存严重不足时,系统为了继续运转,内核会挑选一个进程,将其杀掉,以释放内存,缓解内存不足情况,不过这种保护是有限的,不能完全的保护进程的运行。
在很多情况下,经常会看到还有剩余内存时,oom-killer依旧把进程杀死了,现象是在/var/log/messages日志文件中有如下信息:
Out of Memory: Killed process [PID] [process name].
该问题是low memory耗尽,因为内核使用low memory来跟踪所有的内存分配。
当low memory耗尽,不管high memory剩多少,oom-killer都会杀死进程,以保持系统的正常运行。
在32位CPU下寻址范围是有限的,Linux内核定义了下面三个区域:
# DMA: 0x00000000 - 0x00999999 (0 - 16 MB)
# LowMem: 0x01000000 - 0x037999999 (16 - 896 MB) - size: 880MB
# HighMem: 0x038000000 - <硬件特定>
LowMem区(也叫NORMAL ZONE)共880MB,并且是固定不能变的(除非使用hugemem内核),对于高负荷的系统,可能因为LowMem使用不好而触发了OOM Killer机制。因为内存分配是一个连续的区域,在此时,如果LowMem里存在很多碎片或者LowFree太少,此时无法分配到一块连续的内存区域,就触发了OOM Killer。
查看当前LowFree值:
cat /proc/meminfo | grep LowFree
查看LowMem内存碎片:
cat /proc/buddyinfo
上面这命令需要在2.6内核才有效。
有如下方法可以解决该问题:
1、升级到64位系统,这是最好的方法,因为此时所有的内存都属low memory,如此时提示out of memory,则真的是low memory耗尽,真的OOM了。
2、如必须使用32位系统,那么可以使用hugemem内核,此时内核会以不同的方式分割low/high memory,而大多数情况下会提供足够多的low memory至high memory的映射,此时很简单的一个修复方法是可以安装hugemem内核包,然后重启。
3、如果hugemem内核也用不了,那么我们可以尝试将/proc/sys/vm/lower_zone_protection的值设为250或更大,可使用如下命令查看和设置该值:
cat /proc/sys/vm/lower_zone_protection
echo 250 > /proc/sys/vm/lower_zone_protection
或者可以修改/etc/sysctl.conf文件,以便重启后生效,添加的内容如下:
vm.lower_zone_protection = 250
4、实在没办法,那么我们把oom-killer关掉,不过该选项可能导致系统挂起,故要看实际情况使用。
查看当前的oom-killer的状态:cat /proc/sys/vm/oom-kill
关闭/打开oom-killer:
echo "0" > /proc/sys/vm/oom-kill
echo "1" > /proc/sys/vm/oom-kill
或者直接加到/etc/sysctl.conf文件,内容如下:
vm.oom-kill = 0
此时,当进程被oom-killer尝试杀死而没有成功时,会把相关信息记录到/var/log/messages文件中,信息如下:
"Would have oom-killed but /proc/sys/vm/oom-kill is disabled"
5、或者不把oom-killer关掉,只针对单一进程处理,把某个进程保护起来,此时,我们可以使用如下命令:
echo -17 > /proc/[pid]/oom_adj
/proc/[pid]/oom_adj中oom_adj的取值范围是-17~15,当该值为-17时,系统将不会杀死指定pid的进程,而-16~15则会使得进程的/proc/[pid]/oom_adj值呈指数(K*2^n)形式递增,即它们被杀掉的可能性呈指数递增。针对init(进程号为1)这个进程,无论该值设为多少都不会被杀。
6、参考资料
以上是从网络上查到,结合自己的问题进行下补充:
一开始由于系统配置是2G,而且没有交换分区,所以每天导致out of memory,后来增加了物理内存,并做了交换分区,情况有所改善,但是运行2-3天后还是会出现out of memory的情况,后来分析日志文件messages发现粗体部分,分析是low memory不足导致,后来自己试验用sync ;echo 3 >> /proc/sys/vm/drop_caches可以将内存释放出来,查看/proc/buddyinfo内存释放出来。
Jun 10 13:33:11 xx user.warn kernel: DMA free:3548kB min:68kB low:84kB high:100kB active:0kB inactive:0kB present:16384kB pages_scanned:0 all_unreclaimable? yes
Jun 10 13:33:11 xx user.warn kernel: lowmem_reserve[]: 0 0 880 4080
Jun 10 13:33:11 xx user.warn kernel: DMA32 free:0kB min:0kB low:0kB high:0kB active:0kB inactive:0kB present:0kB pages_scanned:0 all_unreclaimable? no
Jun 10 13:33:11 xx user.warn kernel: lowmem_reserve[]: 0 0 880 4080
Jun 10 13:33:11 xx user.warn kernel: Normal free:1340kB min:3756kB low:4692kB high:5632kB active:0kB inactive:28kB present:901120kB pages_scanned:2456536 all_unreclaimable? yes
Jun 10 13:33:11 xx user.warn kernel: lowmem_reserve[]: 0 0 0 25600
Jun 10 13:33:11 xx user.warn kernel: HighMem free:1615600kB min:512kB low:3928kB high:7344kB active:274112kB inactive:24928kB present:3276800kB pages_scanned:0 all_unreclaimable? no
Jun 10 13:33:11 xx user.warn kernel: lowmem_reserve[]: 0 0 0 0
Jun 10 13:33:11 xx user.warn kernel: DMA: 1*4kB 1*8kB 1*16kB 0*32kB 1*64kB 1*128kB 1*256kB 0*512kB 1*1024kB 1*2048kB 0*4096kB = 3548kB
Jun 10 13:33:11 xx user.warn kernel: DMA32: empty
Jun 10 13:33:11 xx user.warn kernel: Normal: 1*4kB 1*8kB 1*16kB 1*32kB 0*64kB 0*128kB 1*256kB 0*512kB 1*1024kB 0*2048kB 0*4096kB = 1340kB
Jun 10 13:33:11 CHINASOFT user.warn kernel: HighMem: 8192*4kB 7506*8kB 5166*16kB 2932*32kB 1528*64kB 688*128kB 253*256kB 86*512kB 67*1024kB 12*2048kB 234*4096kB = 1615600kB
以上是自己遇到的问题,处理肯定有不对的地方,如果您发现请指正!补充:内核是2.26.16
2014年12月24日星期三
解决Samba访问慢的问题
之前的一台开发机samba访问一直很正常,但是突然有天就变得很慢,现象就是保存一个文件时可能要得10多秒,这实在是受不了。折腾了两天,网上的方法都试了一下,完全没用。今天偶尔发现 /etc/resolv.conf 里面的一台nameserver有点慢,ping都要40ms,然后换了一台快的,ping基本上在1ms以内,然后samba的速度一下就快起来了,秒存文件,爽啊。
2014年9月13日星期六
linux:解决too many open files错误
一大早被叫起来解决故障,悲催啊。就是因为机器设置的max open files太小了,一会就不够了。
登上机器,一看:ulimit -n,结果只有1024. 好吧,临时解决方案:ulimit -n 409600,注意这个命令只对当前shell有效,所以修改后要在当前shell重启进程。
后来运维上线来搞了,方法记录一下:
登上机器,一看:ulimit -n,结果只有1024. 好吧,临时解决方案:ulimit -n 409600,注意这个命令只对当前shell有效,所以修改后要在当前shell重启进程。
后来运维上线来搞了,方法记录一下:
/etc/security/limits.conf
加上:
* soft nofile 65535
* hard nofile 65535
* hard nofile 65535
就ok了。
2014年7月18日星期五
多个进程打开同一个文件,各个进程得到的fd可能是一样的!
两个程序都用open打开同一个文件,然后把fd打印出来,一看,fd怎么是一样的?一下没想出来原因,还去stackoverflow上查了半天。下意识的以为fd是系统唯一的,一个进程占用了这个fd,另一个进程应该就不会有分配到这个fd了。而且看《Unix环境高级编程》里面给出的多进程打开一个文件的例子,fd是不一样的。当时就晕了。
后来在http://linux.die.net/man/3/open上仔细看了一下:
The open() function shall return a file descriptor for the named file that is the lowest file descriptor not currently open for that process
就是说open返回的fd是这个进程内未分配的最小文件描述符,好吧,这样就清楚了。
后来在http://linux.die.net/man/3/open上仔细看了一下:
The open() function shall return a file descriptor for the named file that is the lowest file descriptor not currently open for that process
就是说open返回的fd是这个进程内未分配的最小文件描述符,好吧,这样就清楚了。
想到的其他问题:
1.一个进程如果多次打开同一文件,会得到不同的fd。
2.一个进程内多个线程打开一个文件会得到不同的fd。
3.对于记录锁,一个进程可以提出多个锁请求,即新锁可以替换老锁。一个进程多次打开一个文件,得到多个fd,再对这些fd上锁,这是ok的,即不会出现等锁的情况。
4.继续,一个进程创建了多个线程,多个线程打开一个文件,得到不同fd,众线程对各种的fd设置锁,是不会出现一个线程等待另一个线程的情况。所以,记录锁不能用于线程。
订阅:
博文 (Atom)