版本:MySQL5.5.8 GA
症状:无法启动mysql,在“mysql数据库目录/主机名.err”日志文件中报错 Unknown/unsupported storage engine: InnoDB
原因:MySQL5.5.8 GA默认引擎为InnoDB,而配置文件(my.cnf)中设置了skip-innodb
解决:在配置文件(my.cnf)中设置default-storage-engine=MyISAM
Error:
2013-08-18 21:08:37 21440 [Note] Plugin 'FEDERATED' is disabled.
2013-08-18 21:08:37 21440 [Note] Plugin 'InnoDB' is disabled.
2013-08-18 21:08:37 21440 [ERROR] Unknown/unsupported storage engine: InnoDB
My.cnf修改成这样就Ok了:
#loose-skip-innodb
default-storage-engine = MyISAM
加上#号后启动Ok:
mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.13 Source distribution
参考:http://www.kilobug.com/archives/630
症状:无法启动mysql,在“mysql数据库目录/主机名.err”日志文件中报错 Unknown/unsupported storage engine: InnoDB
原因:MySQL5.5.8 GA默认引擎为InnoDB,而配置文件(my.cnf)中设置了skip-innodb
解决:在配置文件(my.cnf)中设置default-storage-engine=MyISAM
Error:
2013-08-18 21:08:37 21440 [Note] Plugin 'FEDERATED' is disabled.
2013-08-18 21:08:37 21440 [Note] Plugin 'InnoDB' is disabled.
2013-08-18 21:08:37 21440 [ERROR] Unknown/unsupported storage engine: InnoDB
My.cnf修改成这样就Ok了:
#loose-skip-innodb
default-storage-engine = MyISAM
加上#号后启动Ok:
mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.13 Source distribution
参考:http://www.kilobug.com/archives/630
Raspberry Pi 使用DS18B20:
一、硬件准备
1、树莓派(Raspberry Pi)一个
2、DS18B20温度传感器一个(淘宝大概5元左右)
3、4.7kΩ电阻一个 或 DS18B20模块一个(笔者用,淘宝1.5元一个,其实就是店家帮忙把电阻焊好了,接线稍好看些)。
4、杜邦线三根(双头母)
二、接线方式(如图所示)
Raspberry <wbr>Pi <wbr>使用DS18B20温度传感器
三、确认硬件接线是否正确并生效,并读取温度
1、首先升级内核(可忽略,但如果版本较老,可能影响设备读取)
apt-get update
apt-get upgrade
2、确认设备是否生效
sudo modprobe w1-gpio
sudo modprobe w1-therm
cd /sys/bus/w1/devices/
ls
显示结果:
pi@raspberrypi:~$ cd /sys/bus/w1/devices/
pi@raspberrypi:/sys/bus/w1/devices$ ls
28-00000494cb79 w1_bus_master1
28-00000494cb79就是笔者外接的温度传感器设备,但并不是每个客户端都显示一样的,这个是传感器的序列号。
3、查看当前温度
cd 28-00000494cb79
cat w1_slave
显示结果:
70 01 4b 46 7f ff 10 10 e1 : crc=e1 YES
70 01 4b 46 7f ff 10 10 e1 t=23000
第二行的t=23000就是当前的温度值,要换算成摄氏度,除以1000,即当前温度为23000/1000=23摄氏度。
四、用python读取温度值
文件存放:/home/pi/temperature.py
内容如下:
#/home/pi/temperature.py
#打开温度传感器文件
tfile = open("/sys/bus/w1/devices/28-00000494cb79/w1_slave")
#读取文件所有内容
text = tfile.read()
#关闭文件
tfile.close()
#用换行符分割字符串成数组,并取第二行
secondline = text.split("\n")[1]
#用空格分割字符串成数组,并取最后一个,即t=23000
temperaturedata = secondline.split(" ")[9]
#取t=后面的数值,并转换为浮点型
temperature = float(temperaturedata[2:])
#转换单位为摄氏度
temperature = temperature / 1000
#打印值
print temperature
在命令行运行,即可得出结果数值:
python /home/pi/temperature.py
五、上报到yeelink
yeelink是国内比较知名的免费物联网数据平台,国外有COSM(https://cosm.com)。
申请yeelink账号及添加设备和传感器,以及API的学习,本文跳过,请大家自行去学习一下。
根据yeelink API的规则,我们需要提供一个文本文件,内容为一段JSON,如下:
{
“timestamp”:”2012-03-15T16:13:14″,
“value”:294.34
}
若未指定timestamp, 服务器会自动加上当前时间,所以本文的操作不添加该字段
1、修改python,将温度值用JSON格式保存到一个文本文件,全部如下:
#/home/pi/temperature.py
tfile = open("/sys/bus/w1/devices/28-00000494cb79/w1_slave")
text = tfile.read()
tfile.close()
secondline = text.split("\n")[1]
temperaturedata = secondline.split(" ")[9]
temperature = float(temperaturedata[2:])
temperature = temperature / 1000
res = '{"value":%f}' %temperature
output = open('/home/pi/datafile.txt', 'w')
output.write(res)
output.close
python将温度值写入:/home/pi/datafile.txt
2、新增yeelink.sh脚本
文件位置:/home/pi/yeelink.sh
内容如下:
sudo python /home/pi/temperature.py
curl --request POST --data-binary @"/home/pi/datafile.txt" --header"U-ApiKey:XXXXXXXXXXXXXXXX"http://api.yeelink.net/v1.0/device/1969/sensor/2533/datapoints
将U-ApiKey:XXXXXXXXXXXXXXXX替换为自已账户的API Key。
后面的URL也需要替换为自己申请的传感器URL。
3、添加到计划任务
#为脚本增加可执行权限
sudo chmod +x yeelink.sh
#将脚本加入cronjob(计划任务)
sudo crontab -e
#在cornjob文件中添加下面一行,并保存(表示10分钟执行一下脚本,时间可自行修改)
*/10 * * * * /home/pi/yeelink.sh
完了!
我的温度传感器数据展示页面:http://www.yeelink.net/devices/1969
参考文档:
http://www.cl.cam.ac.uk/freshers/raspberrypi/tutorials/temperature/
http://blog.turningdigital.com/2012/09/raspberry-pi-ds18b20-temperature-sensor-rrdtool/
http://webshed.org/wiki/RaspberryPI_DS1820
http://baike.baidu.com/view/1341776.htm
以上来自:http://blog.sina.com.cn/s/blog_3cb6a78c0101a46w.html
————————————————————————————————————————————————
有画图程序值得参考:
blog.turningdigital.com/2012/09/raspberry-pi-ds18b20-temperature-sensor-rrdtool/
一:首先升级内核(可忽略,但如果版本较老,可能影响设备读取)
apt-get update
apt-get upgrade
二:
温度传感器用的是DS18B20,由于树莓派是工作在linux下,所以无法直接使用C来做驱动,因此我使用的是国外大牛做好的驱动,直接编译进内核
具体方式,进入命令行(通过ssh或者直接连显示器)
输入如下命令
sudo wget http://www.frank-buss.de/raspberrypi/kernel-rpi-w1.tgz
sudo tar -xzf kernel-rpi-w1.tgz
sudo rm -f kernel-rpi-w1.tgz
sudo cd /lib/modules
sudo wget http://www.frank-buss.de/raspberrypi/modules-rpi-w1.tgz
sudo tar -xzf modules-rpi-w1.tgz
sudo rm -f modules-rpi-w1.tgz
sudo sync
sudo reboot
然后等待机器重启重新加载1-wire设备的驱动,也就是给18b20的驱动。
重启完成之后,按图所示连接18B20和树莓派:来自:http://www.guokr.com/post/438477/
http://img1.guokr.com/thumbnail/SCe-ZqjIdJeTog3r28g8Ji5COD9U1lS3vnoHAB13aIvdAwAAYAIAAEpQ_590x362.jpg
http://www.guokr.com/post/438477/
The response will either have YES or NO at the end of the first line. If it is yes, then the temperature will be at the end of the second line, in 1/000 degrees C. So, in the example above, the temperature is actually read as 20.687 and then 26.125 degrees C.
If you have more than one Sensor connected, you'll see multiple 28-xxx files. Each one will have the unique serial number so you may want to plug one in at a time, look at what file is created, and label the sensor!
摘录来自:http://learn.adafruit.com/adafruits-raspberry-pi-lesson-11-ds18b20-temperature-sensing/ds18b20
参考:http://www.2fz1.com/?tag=ds18b20
PWM输出:http://www.eeboard.com/bbs/thread-7174-1-1.html
以上就可以实现一个温度控制了。
背景:前面我用过at89s52和ds18B20做过温度传感器,也用tsic506做过,发现单片机里的线太多了(因为有按钮什么的接线,控制电路接通和断开的线等),这个raspberry pi可以通过触摸屏来实现这个按钮,也就减少了线,而且不用com口接至上位机,也就是说可以直接显示出来温度曲线,再就是这个linux有一个watchdog,不用单片机那样用上那个硬件看门狗都可以保证系统不会死,死了linux会拉起来的,稳定性增强了(这块要注意5V的电源一定要好,否则系统一样不稳定,我用欧版I9000的原装电源发现很不错。),外加上一个wifi的usb无线网卡,可以实现发到任何互联网的地方(用php或python等)。
阅读全文
一、硬件准备
1、树莓派(Raspberry Pi)一个
2、DS18B20温度传感器一个(淘宝大概5元左右)
3、4.7kΩ电阻一个 或 DS18B20模块一个(笔者用,淘宝1.5元一个,其实就是店家帮忙把电阻焊好了,接线稍好看些)。
4、杜邦线三根(双头母)
二、接线方式(如图所示)
Raspberry <wbr>Pi <wbr>使用DS18B20温度传感器
三、确认硬件接线是否正确并生效,并读取温度
1、首先升级内核(可忽略,但如果版本较老,可能影响设备读取)
apt-get update
apt-get upgrade
2、确认设备是否生效
sudo modprobe w1-gpio
sudo modprobe w1-therm
cd /sys/bus/w1/devices/
ls
显示结果:
pi@raspberrypi:~$ cd /sys/bus/w1/devices/
pi@raspberrypi:/sys/bus/w1/devices$ ls
28-00000494cb79 w1_bus_master1
28-00000494cb79就是笔者外接的温度传感器设备,但并不是每个客户端都显示一样的,这个是传感器的序列号。
3、查看当前温度
cd 28-00000494cb79
cat w1_slave
显示结果:
70 01 4b 46 7f ff 10 10 e1 : crc=e1 YES
70 01 4b 46 7f ff 10 10 e1 t=23000
第二行的t=23000就是当前的温度值,要换算成摄氏度,除以1000,即当前温度为23000/1000=23摄氏度。
四、用python读取温度值
文件存放:/home/pi/temperature.py
内容如下:
#/home/pi/temperature.py
#打开温度传感器文件
tfile = open("/sys/bus/w1/devices/28-00000494cb79/w1_slave")
#读取文件所有内容
text = tfile.read()
#关闭文件
tfile.close()
#用换行符分割字符串成数组,并取第二行
secondline = text.split("\n")[1]
#用空格分割字符串成数组,并取最后一个,即t=23000
temperaturedata = secondline.split(" ")[9]
#取t=后面的数值,并转换为浮点型
temperature = float(temperaturedata[2:])
#转换单位为摄氏度
temperature = temperature / 1000
#打印值
print temperature
在命令行运行,即可得出结果数值:
python /home/pi/temperature.py
五、上报到yeelink
yeelink是国内比较知名的免费物联网数据平台,国外有COSM(https://cosm.com)。
申请yeelink账号及添加设备和传感器,以及API的学习,本文跳过,请大家自行去学习一下。
根据yeelink API的规则,我们需要提供一个文本文件,内容为一段JSON,如下:
{
“timestamp”:”2012-03-15T16:13:14″,
“value”:294.34
}
若未指定timestamp, 服务器会自动加上当前时间,所以本文的操作不添加该字段
1、修改python,将温度值用JSON格式保存到一个文本文件,全部如下:
#/home/pi/temperature.py
tfile = open("/sys/bus/w1/devices/28-00000494cb79/w1_slave")
text = tfile.read()
tfile.close()
secondline = text.split("\n")[1]
temperaturedata = secondline.split(" ")[9]
temperature = float(temperaturedata[2:])
temperature = temperature / 1000
res = '{"value":%f}' %temperature
output = open('/home/pi/datafile.txt', 'w')
output.write(res)
output.close
python将温度值写入:/home/pi/datafile.txt
2、新增yeelink.sh脚本
文件位置:/home/pi/yeelink.sh
内容如下:
sudo python /home/pi/temperature.py
curl --request POST --data-binary @"/home/pi/datafile.txt" --header"U-ApiKey:XXXXXXXXXXXXXXXX"http://api.yeelink.net/v1.0/device/1969/sensor/2533/datapoints
将U-ApiKey:XXXXXXXXXXXXXXXX替换为自已账户的API Key。
后面的URL也需要替换为自己申请的传感器URL。
3、添加到计划任务
#为脚本增加可执行权限
sudo chmod +x yeelink.sh
#将脚本加入cronjob(计划任务)
sudo crontab -e
#在cornjob文件中添加下面一行,并保存(表示10分钟执行一下脚本,时间可自行修改)
*/10 * * * * /home/pi/yeelink.sh
完了!
我的温度传感器数据展示页面:http://www.yeelink.net/devices/1969
参考文档:
http://www.cl.cam.ac.uk/freshers/raspberrypi/tutorials/temperature/
http://blog.turningdigital.com/2012/09/raspberry-pi-ds18b20-temperature-sensor-rrdtool/
http://webshed.org/wiki/RaspberryPI_DS1820
http://baike.baidu.com/view/1341776.htm
以上来自:http://blog.sina.com.cn/s/blog_3cb6a78c0101a46w.html
————————————————————————————————————————————————
有画图程序值得参考:
blog.turningdigital.com/2012/09/raspberry-pi-ds18b20-temperature-sensor-rrdtool/
一:首先升级内核(可忽略,但如果版本较老,可能影响设备读取)
apt-get update
apt-get upgrade
二:
温度传感器用的是DS18B20,由于树莓派是工作在linux下,所以无法直接使用C来做驱动,因此我使用的是国外大牛做好的驱动,直接编译进内核
具体方式,进入命令行(通过ssh或者直接连显示器)
输入如下命令
sudo wget http://www.frank-buss.de/raspberrypi/kernel-rpi-w1.tgz
sudo tar -xzf kernel-rpi-w1.tgz
sudo rm -f kernel-rpi-w1.tgz
sudo cd /lib/modules
sudo wget http://www.frank-buss.de/raspberrypi/modules-rpi-w1.tgz
sudo tar -xzf modules-rpi-w1.tgz
sudo rm -f modules-rpi-w1.tgz
sudo sync
sudo reboot
然后等待机器重启重新加载1-wire设备的驱动,也就是给18b20的驱动。
重启完成之后,按图所示连接18B20和树莓派:来自:http://www.guokr.com/post/438477/
http://img1.guokr.com/thumbnail/SCe-ZqjIdJeTog3r28g8Ji5COD9U1lS3vnoHAB13aIvdAwAAYAIAAEpQ_590x362.jpg
http://www.guokr.com/post/438477/
The response will either have YES or NO at the end of the first line. If it is yes, then the temperature will be at the end of the second line, in 1/000 degrees C. So, in the example above, the temperature is actually read as 20.687 and then 26.125 degrees C.
If you have more than one Sensor connected, you'll see multiple 28-xxx files. Each one will have the unique serial number so you may want to plug one in at a time, look at what file is created, and label the sensor!
摘录来自:http://learn.adafruit.com/adafruits-raspberry-pi-lesson-11-ds18b20-temperature-sensing/ds18b20
参考:http://www.2fz1.com/?tag=ds18b20
PWM输出:http://www.eeboard.com/bbs/thread-7174-1-1.html
以上就可以实现一个温度控制了。
背景:前面我用过at89s52和ds18B20做过温度传感器,也用tsic506做过,发现单片机里的线太多了(因为有按钮什么的接线,控制电路接通和断开的线等),这个raspberry pi可以通过触摸屏来实现这个按钮,也就减少了线,而且不用com口接至上位机,也就是说可以直接显示出来温度曲线,再就是这个linux有一个watchdog,不用单片机那样用上那个硬件看门狗都可以保证系统不会死,死了linux会拉起来的,稳定性增强了(这块要注意5V的电源一定要好,否则系统一样不稳定,我用欧版I9000的原装电源发现很不错。),外加上一个wifi的usb无线网卡,可以实现发到任何互联网的地方(用php或python等)。
阅读全文
Linux 下僵尸进程的清理方法
Unix/LinuxC技术 jackxiang 2013-8-15 17:58
linux下的程序分析工具——gprof
Unix/LinuxC技术 jackxiang 2013-8-13 18:24
这个更界面化:http://www.cnblogs.com/rocketfan/archive/2009/11/15/1603465.html
GNU gprof 是一款linux平台上的程序分析软件(unix也有prof)。借助gprof可以获得C程序运行期间的统计数据,例如每个函数耗费的时间,函数被调用的次数以及各个函数相互之间的调用关系。gprof可以帮助我们找到程序运行的瓶颈,对占据大量CPU时间的函数进行调优(gprof统计的只是CPU的占用时间,对I/O瓶颈貌似无能为力,耗时甚久的I/O操作很可能只占据极少的CPU时间)。
gprof的使用非常简单,在编译链接的时候加上"-pg"选项,然后按照正常方式运行程序,如果程序正常退出,一个名为gmon.out将会产生。使用gprof可查看gmon.out中的统计结果:
gprof <options> [executable-file] [profile-data-file(s)……] [>outfile]
可通过man gprof 查看各选项含义,通常会加上"-b"选项禁止显示冗长的说明信息。
executable-file如果没有指定,则会默认为a.out。
profile-data-file可跟多个文件,若没有指定,默认gmon.out。
统计信息较多,最好重定向到outfile方便查看。
最终呈现的统计信息包括两张表:flat table和call graph。flat table列出了各个函数的运行时间(不包括子函数)及所占总运行时间的比率,函数的调用次数;call graph还包括函数之间的调用关系,详细列出了每个函数在它的各个子函数上所耗费的时间。
下面一个简单的例子说明一下两张表中各项的含义:
待分析的程序源码:
#define MAX 10000000
void f() {
long long sum = 0;
for (long long i=0;i<MAX;i++)
sum += i;
}
void g() {
long long sum = 0;
for (long long i=0;i<MAX;i++)
sum += i;
f();
}
int main() {
long long sum = 0;
for (long long i=0;i<MAX;i++)
sum += i;
f();
g();
}
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
50.00 0.07 0.07 2 35.00 35.00 f()
28.57 0.11 0.04 1 40.00 75.00 g()
21.43 0.14 0.03 main
% time:各个函数占用的时间比率(不包括子函数),这一列加起来应该为100%
cumulative seconds:累积时间,当前行减去上一行即为当前函数耗费时间
self seconds:当前函数耗费时间(不包括子函数)
self calls:调用次数
ms/call:调用一次耗费的平均时间(不包括子函数),单位毫秒
total ms/call:同上,但包括子函数
name:函数名
call graph:
granularity: each sample hit covers 4 byte(s) for 7.14% of 0.14 seconds
index % time self children called name
<spontaneous>
[1] 100.0 0.03 0.11 main [1]
0.04 0.04 1/1 g() [2]
0.04 0.00 1/2 f() [3]
-----------------------------------------------
0.04 0.04 1/1 main [1]
[2] 53.6 0.04 0.04 1 g() [2]
0.04 0.00 1/2 f() [3]
-----------------------------------------------
0.04 0.00 1/2 g() [2]
0.04 0.00 1/2 main [1]
[3] 50.0 0.07 0.00 2 f() [3]
-----------------------------------------------
每个函数都分配了一个index,index按升序排列,一个函数对应一个entry,两个entry之间用虚线隔开。
在每个entry中,以[index]起头的行称为primary line。primary line上面的行称为caller's line,列举的是调用该函数的函数;下面的行subroutine's line列举的是该函数调用的子函数。这三种line的各项名称虽然相同,但有着截然不同的含义。
以下都以第二个entry为例说明:
primary line
index % time self children called name
[2] 53.6 0.04 0.04 1 g() [2]
%time:g()耗费的时间比率。该比率包括了调用的f(),因此各个entry的该项数字加起来不等于100%。
self:同flat table的self seconds。
children:f()耗费的时间。下面的subroutines's line 的self项和children项之和应等于该数值。
called:只被调用了一次。
subroutine's line
index % time self children called name
0.04 0.00 1/2 f() [3]
self:f()被g()调用过程中,f()的耗费时间0.04s。
children:f()被g()调用过程中,f()中的子函数耗费时间为0。
called:f()一共被调用了2次,其中有1次被g()调用。
caller's line
index % time self children called name
0.04 0.04 1/1 main [1]
self:g()被main()调用过程中,g()的耗费时间。
children:g()被main()调用过程中,g()中的子函数耗费的时间。
called:g()一共被调用了1次,其中1次是被main()调用的。
gprof的基本原理
类似于gdb,gprof需要对待分析的程序做一些改动,因此在程序编译的时候需要加上"-pg"选项,如果程序的某个模块在编译的时候没有加上"-pg",则该模块的函数会被排除在统计范围之外。比如想要查看库函数的profiling,则需在链接库函数的时候用“-lc_p"代替”-lc"(gprof是各个类UNIX的标准工具,系统自带的链接库通常有两个版本,它们的区别在于编译的时候是否加上了"-pg"。用-lc_p等于告诉编译器选择加上了"-pg"的那个版本)。
加上"-pg"选项后,程序的入口会于main()之前调用monstartup(),主要是申请内存存储接下来获取的统计信息。
在每个函数中会调用mcount(),主要是在函数的堆栈中查询父函数和子函数的地址并保存下来。
最后会在程序退出前调用_mcleanup(),将统计结果保存到gmon.out中,并完成清除工作。
gprof统计各个函数的运行时间是采用的抽样的方法,周期性的查看Program counter指向哪一个函数的地址段,并把结果以直方图的形式保存下来。
PS:
有人建议在编译时不要加上"-g"选项,因为这样可能会影响分析结果。
通常gprof的采样周期是0.01s,统计项越接近这个值误差可能越大。若函数的运行时间低于0.01S,统计值会显示为0。
关于这一主题的有用链接:
http://www.cs.utah.edu/dept/old/texinfo/as/gprof_toc.html:关于options, flat table, call graph有更详细的论述。
http://wiki.waterlin.org/Cpp/gprof.html:对gprof的实现原理论述得很清晰。
http://sam.zoy.org/writings/programming/gprof.html:对多线程profiling。
http://linuxfocus.org/English/March2005/article371.meta.shtml:提到了perl和java的profiling方法。
来自:http://blog.sina.com.cn/s/blog_6608391701013phr.html
GNU gprof 是一款linux平台上的程序分析软件(unix也有prof)。借助gprof可以获得C程序运行期间的统计数据,例如每个函数耗费的时间,函数被调用的次数以及各个函数相互之间的调用关系。gprof可以帮助我们找到程序运行的瓶颈,对占据大量CPU时间的函数进行调优(gprof统计的只是CPU的占用时间,对I/O瓶颈貌似无能为力,耗时甚久的I/O操作很可能只占据极少的CPU时间)。
gprof的使用非常简单,在编译链接的时候加上"-pg"选项,然后按照正常方式运行程序,如果程序正常退出,一个名为gmon.out将会产生。使用gprof可查看gmon.out中的统计结果:
gprof <options> [executable-file] [profile-data-file(s)……] [>outfile]
可通过man gprof 查看各选项含义,通常会加上"-b"选项禁止显示冗长的说明信息。
executable-file如果没有指定,则会默认为a.out。
profile-data-file可跟多个文件,若没有指定,默认gmon.out。
统计信息较多,最好重定向到outfile方便查看。
最终呈现的统计信息包括两张表:flat table和call graph。flat table列出了各个函数的运行时间(不包括子函数)及所占总运行时间的比率,函数的调用次数;call graph还包括函数之间的调用关系,详细列出了每个函数在它的各个子函数上所耗费的时间。
下面一个简单的例子说明一下两张表中各项的含义:
待分析的程序源码:
#define MAX 10000000
void f() {
long long sum = 0;
for (long long i=0;i<MAX;i++)
sum += i;
}
void g() {
long long sum = 0;
for (long long i=0;i<MAX;i++)
sum += i;
f();
}
int main() {
long long sum = 0;
for (long long i=0;i<MAX;i++)
sum += i;
f();
g();
}
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
50.00 0.07 0.07 2 35.00 35.00 f()
28.57 0.11 0.04 1 40.00 75.00 g()
21.43 0.14 0.03 main
% time:各个函数占用的时间比率(不包括子函数),这一列加起来应该为100%
cumulative seconds:累积时间,当前行减去上一行即为当前函数耗费时间
self seconds:当前函数耗费时间(不包括子函数)
self calls:调用次数
ms/call:调用一次耗费的平均时间(不包括子函数),单位毫秒
total ms/call:同上,但包括子函数
name:函数名
call graph:
granularity: each sample hit covers 4 byte(s) for 7.14% of 0.14 seconds
index % time self children called name
<spontaneous>
[1] 100.0 0.03 0.11 main [1]
0.04 0.04 1/1 g() [2]
0.04 0.00 1/2 f() [3]
-----------------------------------------------
0.04 0.04 1/1 main [1]
[2] 53.6 0.04 0.04 1 g() [2]
0.04 0.00 1/2 f() [3]
-----------------------------------------------
0.04 0.00 1/2 g() [2]
0.04 0.00 1/2 main [1]
[3] 50.0 0.07 0.00 2 f() [3]
-----------------------------------------------
每个函数都分配了一个index,index按升序排列,一个函数对应一个entry,两个entry之间用虚线隔开。
在每个entry中,以[index]起头的行称为primary line。primary line上面的行称为caller's line,列举的是调用该函数的函数;下面的行subroutine's line列举的是该函数调用的子函数。这三种line的各项名称虽然相同,但有着截然不同的含义。
以下都以第二个entry为例说明:
primary line
index % time self children called name
[2] 53.6 0.04 0.04 1 g() [2]
%time:g()耗费的时间比率。该比率包括了调用的f(),因此各个entry的该项数字加起来不等于100%。
self:同flat table的self seconds。
children:f()耗费的时间。下面的subroutines's line 的self项和children项之和应等于该数值。
called:只被调用了一次。
subroutine's line
index % time self children called name
0.04 0.00 1/2 f() [3]
self:f()被g()调用过程中,f()的耗费时间0.04s。
children:f()被g()调用过程中,f()中的子函数耗费时间为0。
called:f()一共被调用了2次,其中有1次被g()调用。
caller's line
index % time self children called name
0.04 0.04 1/1 main [1]
self:g()被main()调用过程中,g()的耗费时间。
children:g()被main()调用过程中,g()中的子函数耗费的时间。
called:g()一共被调用了1次,其中1次是被main()调用的。
gprof的基本原理
类似于gdb,gprof需要对待分析的程序做一些改动,因此在程序编译的时候需要加上"-pg"选项,如果程序的某个模块在编译的时候没有加上"-pg",则该模块的函数会被排除在统计范围之外。比如想要查看库函数的profiling,则需在链接库函数的时候用“-lc_p"代替”-lc"(gprof是各个类UNIX的标准工具,系统自带的链接库通常有两个版本,它们的区别在于编译的时候是否加上了"-pg"。用-lc_p等于告诉编译器选择加上了"-pg"的那个版本)。
加上"-pg"选项后,程序的入口会于main()之前调用monstartup(),主要是申请内存存储接下来获取的统计信息。
在每个函数中会调用mcount(),主要是在函数的堆栈中查询父函数和子函数的地址并保存下来。
最后会在程序退出前调用_mcleanup(),将统计结果保存到gmon.out中,并完成清除工作。
gprof统计各个函数的运行时间是采用的抽样的方法,周期性的查看Program counter指向哪一个函数的地址段,并把结果以直方图的形式保存下来。
PS:
有人建议在编译时不要加上"-g"选项,因为这样可能会影响分析结果。
通常gprof的采样周期是0.01s,统计项越接近这个值误差可能越大。若函数的运行时间低于0.01S,统计值会显示为0。
关于这一主题的有用链接:
http://www.cs.utah.edu/dept/old/texinfo/as/gprof_toc.html:关于options, flat table, call graph有更详细的论述。
http://wiki.waterlin.org/Cpp/gprof.html:对gprof的实现原理论述得很清晰。
http://sam.zoy.org/writings/programming/gprof.html:对多线程profiling。
http://linuxfocus.org/English/March2005/article371.meta.shtml:提到了perl和java的profiling方法。
来自:http://blog.sina.com.cn/s/blog_6608391701013phr.html
PHP做守护进程出现了内存不够用的情况,有待排查。
Php/Js/Shell/Go jackxiang 2013-8-13 18:19
Allowed memory size of 134217728 bytes exhausted
/usr/local/php/bin/php -i|grep mem
memory_limit => 128M => 128M(换成小b也就是:134217728 bytes )
运行一段时间后就出现:
ErrorException [ 1 ]: Allowed memory size of 134217728 bytes exhausted (tried to allocate 8192 bytes) ~ SYS_PATH/httpsqs.php [ 106 ]
如何测定脚本占用的内存? 有时候我们想知道程序执行到某个特定阶段时到底占用了多大内存,为此PHP提供了函数memory_get_usage()。这个函数只有当PHP编译时使用了--enable-memory-limit参数时才有效。 Xdebug同样提供了一个函数xdebug_memory_usage()来实现这样的功能,另外xdebug还提供了一个xdebug_peak_memory_usage()函数来查看内存占用的峰值。 如何检测代码中的不足? 有时候代码没有明显的编写错误,没有显示任何错误信息(如error、warning、notice等),但是这不表明代码就是正确无误的。有时候可能某段代码执行时间过长,占用内存过多以致于影响整个系统的效率,我们没有办法直接看出来是哪部份代码出了问题。这时候我们希望把代码的每个阶段的运行情况都监控起来,写到日志文件中去,运行一段时间后再进行分析,找到问题所在。 回忆一下,之前我们编辑php.ini文件 加入 [Xdebug] xdebug.profiler_enable=on xdebug.trace_output_dir="I:\Projects\xdebug" xdebug.profiler_output_dir="I:\Projects\xdebug" 这几行,目的就在于把执行情况的分析文件写入到”I:\Projects\xdebug”目录中去(你可以替换成任何你想设定的目录)。如果你执行某段程序后,再打开相应的目录,可以发现生成了一堆文件,例如cachegrind.out.1169585776这种格式命名的文件。这些就是Xdebug生成的分析文件。用编辑器打开你可以看到很多程序运行的相关细节信息,不过很显然这样看太累了,我们需要用图形化的软件来查看。 在Windows平台下,可以用WinCacheGrind(*我修改的*下载地址http://sourceforge.net/projects/wincachegrind/)这个软件来打开这些文件。可以直观漂亮地显示其中内容:
非常漂亮,我们很直观地看到index.php中我们调用了一个函数testXdebug(),testXdebug()中又调用了requireFile()函数。这样我们就可以非常方便地查看整个脚本的程序结构。 另外,我们还可以看到每个函数被调用的次数及执行所花费的时间!这对于测试程序性能非常有用。
摘录自:http://hi.baidu.com/icejmx/item/2af1a6a6f7a6ff248819d314
该引用来源:
http://blog.csdn.net/Haohappy2004/article/details/893060
后记:
内存泄漏不是光是用php做daemon,有时fastcgi本身也出现泄漏的情况,但:
PHP是用GC的,很难跟踪
一般都是用Worker进程管理的方式......
所以,php要想做这一块和c来说还是有差距的,至少在工具上要跟得上才行。
近来发现有像c内存检测的valgrind工具的扩展,可以试下有空:
github上找到: php-valgrind. 这个工具主要是为PHP脚本提供了可以在脚本中开启Valgrind(严格说是Callgrind)的Profile能力
DownLoad:
https://github.com/laruence/php-valgrind
使用参考:http://www.laruence.com/2013/08/14/2899.html
http://lutaf.com/136.htm
内存泄露排查非常困难
因为代码规模非常大,想靠做code review的方式来查基本上不可能
php并非运行在虚拟机上,没有什么官方的monitor(类似java hprof,JVM Monitor等)
在互联网上搜索,找不到任何答案
解决php内存泄露问题:
http://itindex.net/detail/43004-php-%E5%86%85%E5%AD%98-%E9%97%AE%E9%A2%98
后补,对php编写时注意,有可能较大限度的减少内存溢出,如下:
============================Allowed memory size of xxx bytes
PHP内存溢出Allowed memory size of 解决办法 :
以前追踪过这个问题,但是那个时候工具用的不太好,没看的这么细,这次搞的比较细,修正了偶以前的看法
.于是写小文一篇总结一下.
PHP偶尔会爆一下如下 错误Allowed memory size of xxx bytes exhausted at xxx:xxx (tried to
allocate xxx bytes)
不想看原理的,直接跳到最后看总结.
这个报错信息的意思是是说,若ini配置的memory_limit(内存限制) 大于 AG(allocated_memory),就报错
AG(allocated_memory) += rs;
if (AG(memory_limit)<AG(allocated_memory)) {
int php_mem_limit = AG(memory_limit);
AG(allocated_memory) -= rs;
if (EG(in_execution) && AG(memory_limit)+1048576 > AG(allocated_memory)){
AG(memory_limit) = AG(allocated_memory) + 1048576;
if (file) {
zend_error(E_ERROR,"Allowed memory size of %d bytes exhausted
at %s:%d (tried to allocate %d bytes)", php_mem_limit, file, lineno, s);
} else {
zend_error(E_ERROR,"Allowed memory size of %d bytes exhausted
(tried to allocate %d bytes)", php_mem_limit, s);
}
} else {
if (file) {
fprintf(stderr, "Allowed memory size of %d bytes exhausted
at %s:%d (tried to allocate %d bytes)n", php_mem_limit, file, lineno, s);
} else {
fprintf(stderr, "Allowed memory size of %d bytes exhausted
(tried to allocate %d bytes)n", php_mem_limit, s);
}
exit(1);
}
}
memory_limit很简单,就是PHP可用的内存..AG(allocated_memory)是什么呢?是不是已经使用的内存,恩,
我们用代码验证一下
PHP_FUNCTION(memory_get_usage) {
RETURN_LONG(AG(allocated_memory));
}
这下就清晰明了,还不懂的,查php手册,看memory_get_usage的说明
到底什么时候设置AG(allocated_memory)呢,具体代码就不贴了,太繁琐,是在emalloc函数中调用了第一段
代码,看第一行代码,那里的rs就是每次tried to allocate %d bytes对应的s变量(你要申请的实际空间)
的align对齐,具体计算方法:rs = (s+7) & ~0x7,也就是必须是8的倍数,不足则补足,这样做的好处是符合
64位机器的要求,可以加速运算,例如 s =1,那么运算出来的rs =8 ,具体的,可以自己用PHP写个函数计算
(0×7是16进制写法).
总结:既然知道了怎么回事,就好解决了,在开启 –enable-memory-limit情况下,会出这个错误,把配置文
件直接设置memory_limit,或者在代码中设置ini_set(‘memory_limit’, ‘value’)都可以,省事的办法
就是设置配置文件(如php.ini)
而且建议开启–enable-memory-limit,若这个不开启,PHP的内存限制就处于”裸跑”状态,可能会出现著
名的out of memory错误.
使用脚本语言最大的好处之一就是可利用其拥有的自动垃圾回收机制(释放内存)。你不需要在使用完变
量后做任何释放内存的处理,PHP会帮你完成。
当然,我们可以按自己的意愿调用 unset() 函数来释放内存,但通常不需要这么做。
不过在PHP里,至少有一种情况内存不会得到自动释放,即便是手动调用 unset()。详情可考:
http://bugs.php.net/bug.php?id=33595。
问题症状
如果两个对象之间存在着相互引用的关系,如“父对象-子对象”,对父对象调用 unset() 不会释放在子
对象中引用父对象的内存(即便父对象被垃圾回收,也不行)。
有些糊涂了?我们来看下面的这段代码:
<?php
class Foo {
function __construct()
{
$this->bar = new Bar($this);
}
}
class Bar {
function __construct($foo = null)
{
$this->foo = $foo;
}
}
while (true) {
$foo = new Foo();
unset($foo);
echo number_format(memory_get_usage()) . "\n";
}
?>
运行这段代码,你会看到内存使用率越来越高越来越高,直到用光光。
...
33,551,616
33,551,976
33,552,336
33,552,696
PHP Fatal error: Allowed memory size of 33554432 bytes exhausted
(tried to allocate 16 bytes) in memleak.php on line 17
对大部分PHP程序员来讲这种情况不算是什么问题。
可如果你在一个长期运行的代码中使用到了一大堆相互引用的对象,尤其是在对象相对较大的情况下,内
存会迅速地消耗殆尽。
Userland解决方案
虽然有些乏味、不优雅,但之前提到的 bugs.php.net 链接中提供了一个解决方案。
这个方案在释放对象前使用一个 destructor 方法以达到目的。Destructor 方法可将所有内部的父对象
引用全部清除,也就是说可以将这部分本来会溢出的内存释放掉。
以下是“修复后”的代码:
<?php
class Foo {
function __construct()
{
$this->bar = new Bar($this);
}
function __destruct()
{
unset($this->bar);
}
}
class Bar {
function __construct($foo = null)
{
$this->foo = $foo;
}
}
while (true) {
$foo = new Foo();
$foo->__destruct();
unset($foo);
echo number_format(memory_get_usage()) . "\n";
}
?>
注意那个新增的 Foo::__destruct()方法,以及在释放对象前对 $foo->__destruct() 的调用。现在这
段代码解决了内存使用率一直增加的问题,这么一来,代码就可以很好的工作了。
PHP内核解决方案?
为什么会有内存溢出的发生?我对PHP内核方面的研究并不精通,但可以确定的是此问题与引用计数有关
系。
在 $bar 中引用 $foo 的引用计数不会因为父对象 $foo 被释放而递减,这时PHP认为你仍需要 $foo 对
象,也就不会释放这部分的内存……大概是这样。
这里确实可以看出我的无知,但大体意思是:一个引用计数没有递减,所以一些内存永远得不到释放。
在前面提到的 bugs.php.net 链接中我看到修改垃圾回收的过程将会牺牲极大的性能,因为我对引用计数
了解不多,所以我认为这是真的。
与其改变垃圾回收的过程,为什么不用 unset() 对内部对象做释放的工作呢?(或者在释放对象的时候
调用 __destruct()?)
也许PHP内核开发者可以在此或其他地方,对这种垃圾回收处理机制做出修改。
更新:Martin Fjordvald 在评论中提到了一个由 David Wang 为垃圾回收所写的补丁(其实它看起来更
像“一整块布”——非常巨大。详情参见此邮件结尾的CVS导出信息。)确实存在(一封邮件),并受到
了PHP内核开发成员的关注。问题是这个补丁要不要放到PHP5.3中并未得到太多支持。我觉得一个不错的
折中方案就是在 unset() 函数中调用对象中的 __destruct() 方法;
========================内存溢出解决方案
在做数据统计分析时,经常会遇到大数组,可能会发生内存溢出,这里分享一下我的解决方案。还是用例子来说明这个问题,如下:
假定日志中存放的记录数为500000条,那么解决方案如下:
ini_set(‘memory_limit’,’64M’); //重置php可以使用的内存大小为64M,一般在远程主机上是不能修改php.ini文件的,只能通过程序设置。注:在safe_mode(安全模式)下,ini_set失效
set_time_limit(600);//设置超时限制为6分钟
$farr = $Uarr = $Marr = $IParr = $data = $_sub = array();
$spt = ”$@#!$”;
$root = ”/Data/webapps/VisitLog”;
$path = $dpath = $fpath = NULL;
$path = $root.”/”.date(“Y-m”,$timestamp);
$dpath = $path.”/”.date(“m-d”,$timestamp);
for($j=0;$j<24;$j++){
$v = ($j < 10) ? ”0″.$j : $j;
$gpath = $dpath.”/”.$v.”.php”;
if(!file_exists($gpath)){
continue;
} else {
$arr = file($gpath);////将文件读入数组中
array_shift($arr);//移出第一个单元-》<?php exit;?>
$farr = array_merge($farr,$arr);
unset($arr);
}
}
if(empty($this->farr)){
echo ”<p><center>没有相关记录!</center></p>”;
exit;
}
while(!empty($farr)){
$_sub = array_splice($farr, 0, 10000); //每次取出$farr中1000个
for($i=0,$scount=count($_sub);$i<$scount;$i++){
$arr = explode($spt,$_sub[$i]);
$Uarr[] = $arr[1]; //vurl
$Marr[] = $arr[2]; //vmark
$IParr[] = $arr[3].” |$nbsp;”.$arr[1]; //IP
}
unset($_sub);//用完及时销毁
}
unset($farr);
这里,不难看出,一方面,我们要增加PHP可用内存大小,另一方面,只要我们想办法对数组进行分批处理,分而治之,将用过的变量及时销毁(unset),一般是不会出现溢出问题的。
另外,为了节省PHP程序内存损耗,我们应当尽可能减少静态变量的使用,在需要数据重用时,可以考虑使用引用(&)。再一点就是:数据库操作完成后,要马上关闭连接;一个对象使用完,要及时调用析构函数(__destruct())。
============================unset销毁变量并释放内存问题
PHP的unset()函数用来清除、销毁变量,不用的变量,我们可以用unset()将它销毁。但是某些时候,用unset()却无法达到销毁变 量占用的内存!我们先看一个例子:
<?php
$s=str_repeat('1',255); //产生由255个1组成的字符串
$m=memory_get_usage(); //获取当前占用内存
unset($s);
$mm=memory_get_usage(); //unset()后再查看当前占用内存
echo $m-$mm;
?>
最后输出unset()之前占用内存减去unset()之后占用内存,如果是正数,那么说明unset($s)已经将$s从内存中销毁(或者说,unset()之后内存占用减少了),可是我在PHP5和windows平台下,得到的结果是:0。这是否可以说明,unset($s)并没有起 到销毁变量$s所占用内存的作用呢?我们再作下面的例子:
<?php
$s=str_repeat('1',256); //产生由256个1组成的字符串
$m=memory_get_usage(); //获取当前占用内存
unset($s);
$mm=memory_get_usage(); //unset()后再查看当前占用内存
echo $m-$mm;
?>
这个例子,和上面的例子几乎相同,唯一的不同是,$s由256个1组成,即比第一个例子多了一个1,得到结果是:272。这是否可以说 明,unset($s)已经将$s所占用的内存销毁了?
通过上面两个例子,我们可以得出以下结论:
结论一、unset()函数只能在变量值占用内存空间超过256字节时才会释放内存空间。
那么是不是只要变量值超过256,使用unset就可以释放内存空间呢?我们再通过一个例子来测试一下:
<?php
$s=str_repeat('1',256); //这和第二个例子完全相同
$p=&$s;
$m=memory_get_usage();
unset($s); //销毁$s
$mm=memory_get_usage();
echo $p.'<br />';
echo $m-$mm;
?>
刷新页面,我们看到第一行有256个1,第二行是0,按理说我们已经销毁了$s,而$p只是引用$s的变量,应该是没有内容了,另 外,unset($s)前后内存占用没变化!现在我们再做以下的例子:
<?php
$s=str_repeat('1',256); //这和第二个例子完全相同
$p=&$s;
$m=memory_get_usage();
$s=null; //设置$s为null
$mm=memory_get_usage();
echo $p.'<br />';
echo $m-$mm;
?>
现在刷新页面,我们看到,输出$p已经是没有内容了,unset()前后内存占用量之差是272,即已经清除了变量占用的内存。本例中的$s=null也 可以换成unset(),如下:
<?php
$s=str_repeat('1',256); //这和第二个例子完全相同
$p=&$s;
$m=memory_get_usage();
unset($s); //销毁$s
unset($p);
$mm=memory_get_usage();
echo $p.'<br />';
echo $m-$mm;
?>
我们将$s和$p都使用unset()销毁,这时再看内存占用量之差也是272,说明这样也可以释放内存。那么,我们可以得到另外一条结论:
结论二、只有当指向该变量的所有变量(如引用变量)都被销毁后,才会释放内存。
来自:http://zhengdl126.iteye.com/blog/1112231
/usr/local/php/bin/php -i|grep mem
memory_limit => 128M => 128M(换成小b也就是:134217728 bytes )
运行一段时间后就出现:
ErrorException [ 1 ]: Allowed memory size of 134217728 bytes exhausted (tried to allocate 8192 bytes) ~ SYS_PATH/httpsqs.php [ 106 ]
如何测定脚本占用的内存? 有时候我们想知道程序执行到某个特定阶段时到底占用了多大内存,为此PHP提供了函数memory_get_usage()。这个函数只有当PHP编译时使用了--enable-memory-limit参数时才有效。 Xdebug同样提供了一个函数xdebug_memory_usage()来实现这样的功能,另外xdebug还提供了一个xdebug_peak_memory_usage()函数来查看内存占用的峰值。 如何检测代码中的不足? 有时候代码没有明显的编写错误,没有显示任何错误信息(如error、warning、notice等),但是这不表明代码就是正确无误的。有时候可能某段代码执行时间过长,占用内存过多以致于影响整个系统的效率,我们没有办法直接看出来是哪部份代码出了问题。这时候我们希望把代码的每个阶段的运行情况都监控起来,写到日志文件中去,运行一段时间后再进行分析,找到问题所在。 回忆一下,之前我们编辑php.ini文件 加入 [Xdebug] xdebug.profiler_enable=on xdebug.trace_output_dir="I:\Projects\xdebug" xdebug.profiler_output_dir="I:\Projects\xdebug" 这几行,目的就在于把执行情况的分析文件写入到”I:\Projects\xdebug”目录中去(你可以替换成任何你想设定的目录)。如果你执行某段程序后,再打开相应的目录,可以发现生成了一堆文件,例如cachegrind.out.1169585776这种格式命名的文件。这些就是Xdebug生成的分析文件。用编辑器打开你可以看到很多程序运行的相关细节信息,不过很显然这样看太累了,我们需要用图形化的软件来查看。 在Windows平台下,可以用WinCacheGrind(*我修改的*下载地址http://sourceforge.net/projects/wincachegrind/)这个软件来打开这些文件。可以直观漂亮地显示其中内容:
非常漂亮,我们很直观地看到index.php中我们调用了一个函数testXdebug(),testXdebug()中又调用了requireFile()函数。这样我们就可以非常方便地查看整个脚本的程序结构。 另外,我们还可以看到每个函数被调用的次数及执行所花费的时间!这对于测试程序性能非常有用。
摘录自:http://hi.baidu.com/icejmx/item/2af1a6a6f7a6ff248819d314
该引用来源:
http://blog.csdn.net/Haohappy2004/article/details/893060
后记:
内存泄漏不是光是用php做daemon,有时fastcgi本身也出现泄漏的情况,但:
PHP是用GC的,很难跟踪
一般都是用Worker进程管理的方式......
所以,php要想做这一块和c来说还是有差距的,至少在工具上要跟得上才行。
近来发现有像c内存检测的valgrind工具的扩展,可以试下有空:
github上找到: php-valgrind. 这个工具主要是为PHP脚本提供了可以在脚本中开启Valgrind(严格说是Callgrind)的Profile能力
DownLoad:
https://github.com/laruence/php-valgrind
使用参考:http://www.laruence.com/2013/08/14/2899.html
http://lutaf.com/136.htm
内存泄露排查非常困难
因为代码规模非常大,想靠做code review的方式来查基本上不可能
php并非运行在虚拟机上,没有什么官方的monitor(类似java hprof,JVM Monitor等)
在互联网上搜索,找不到任何答案
解决php内存泄露问题:
http://itindex.net/detail/43004-php-%E5%86%85%E5%AD%98-%E9%97%AE%E9%A2%98
后补,对php编写时注意,有可能较大限度的减少内存溢出,如下:
============================Allowed memory size of xxx bytes
PHP内存溢出Allowed memory size of 解决办法 :
以前追踪过这个问题,但是那个时候工具用的不太好,没看的这么细,这次搞的比较细,修正了偶以前的看法
.于是写小文一篇总结一下.
PHP偶尔会爆一下如下 错误Allowed memory size of xxx bytes exhausted at xxx:xxx (tried to
allocate xxx bytes)
不想看原理的,直接跳到最后看总结.
这个报错信息的意思是是说,若ini配置的memory_limit(内存限制) 大于 AG(allocated_memory),就报错
AG(allocated_memory) += rs;
if (AG(memory_limit)<AG(allocated_memory)) {
int php_mem_limit = AG(memory_limit);
AG(allocated_memory) -= rs;
if (EG(in_execution) && AG(memory_limit)+1048576 > AG(allocated_memory)){
AG(memory_limit) = AG(allocated_memory) + 1048576;
if (file) {
zend_error(E_ERROR,"Allowed memory size of %d bytes exhausted
at %s:%d (tried to allocate %d bytes)", php_mem_limit, file, lineno, s);
} else {
zend_error(E_ERROR,"Allowed memory size of %d bytes exhausted
(tried to allocate %d bytes)", php_mem_limit, s);
}
} else {
if (file) {
fprintf(stderr, "Allowed memory size of %d bytes exhausted
at %s:%d (tried to allocate %d bytes)n", php_mem_limit, file, lineno, s);
} else {
fprintf(stderr, "Allowed memory size of %d bytes exhausted
(tried to allocate %d bytes)n", php_mem_limit, s);
}
exit(1);
}
}
memory_limit很简单,就是PHP可用的内存..AG(allocated_memory)是什么呢?是不是已经使用的内存,恩,
我们用代码验证一下
PHP_FUNCTION(memory_get_usage) {
RETURN_LONG(AG(allocated_memory));
}
这下就清晰明了,还不懂的,查php手册,看memory_get_usage的说明
到底什么时候设置AG(allocated_memory)呢,具体代码就不贴了,太繁琐,是在emalloc函数中调用了第一段
代码,看第一行代码,那里的rs就是每次tried to allocate %d bytes对应的s变量(你要申请的实际空间)
的align对齐,具体计算方法:rs = (s+7) & ~0x7,也就是必须是8的倍数,不足则补足,这样做的好处是符合
64位机器的要求,可以加速运算,例如 s =1,那么运算出来的rs =8 ,具体的,可以自己用PHP写个函数计算
(0×7是16进制写法).
总结:既然知道了怎么回事,就好解决了,在开启 –enable-memory-limit情况下,会出这个错误,把配置文
件直接设置memory_limit,或者在代码中设置ini_set(‘memory_limit’, ‘value’)都可以,省事的办法
就是设置配置文件(如php.ini)
而且建议开启–enable-memory-limit,若这个不开启,PHP的内存限制就处于”裸跑”状态,可能会出现著
名的out of memory错误.
使用脚本语言最大的好处之一就是可利用其拥有的自动垃圾回收机制(释放内存)。你不需要在使用完变
量后做任何释放内存的处理,PHP会帮你完成。
当然,我们可以按自己的意愿调用 unset() 函数来释放内存,但通常不需要这么做。
不过在PHP里,至少有一种情况内存不会得到自动释放,即便是手动调用 unset()。详情可考:
http://bugs.php.net/bug.php?id=33595。
问题症状
如果两个对象之间存在着相互引用的关系,如“父对象-子对象”,对父对象调用 unset() 不会释放在子
对象中引用父对象的内存(即便父对象被垃圾回收,也不行)。
有些糊涂了?我们来看下面的这段代码:
<?php
class Foo {
function __construct()
{
$this->bar = new Bar($this);
}
}
class Bar {
function __construct($foo = null)
{
$this->foo = $foo;
}
}
while (true) {
$foo = new Foo();
unset($foo);
echo number_format(memory_get_usage()) . "\n";
}
?>
运行这段代码,你会看到内存使用率越来越高越来越高,直到用光光。
...
33,551,616
33,551,976
33,552,336
33,552,696
PHP Fatal error: Allowed memory size of 33554432 bytes exhausted
(tried to allocate 16 bytes) in memleak.php on line 17
对大部分PHP程序员来讲这种情况不算是什么问题。
可如果你在一个长期运行的代码中使用到了一大堆相互引用的对象,尤其是在对象相对较大的情况下,内
存会迅速地消耗殆尽。
Userland解决方案
虽然有些乏味、不优雅,但之前提到的 bugs.php.net 链接中提供了一个解决方案。
这个方案在释放对象前使用一个 destructor 方法以达到目的。Destructor 方法可将所有内部的父对象
引用全部清除,也就是说可以将这部分本来会溢出的内存释放掉。
以下是“修复后”的代码:
<?php
class Foo {
function __construct()
{
$this->bar = new Bar($this);
}
function __destruct()
{
unset($this->bar);
}
}
class Bar {
function __construct($foo = null)
{
$this->foo = $foo;
}
}
while (true) {
$foo = new Foo();
$foo->__destruct();
unset($foo);
echo number_format(memory_get_usage()) . "\n";
}
?>
注意那个新增的 Foo::__destruct()方法,以及在释放对象前对 $foo->__destruct() 的调用。现在这
段代码解决了内存使用率一直增加的问题,这么一来,代码就可以很好的工作了。
PHP内核解决方案?
为什么会有内存溢出的发生?我对PHP内核方面的研究并不精通,但可以确定的是此问题与引用计数有关
系。
在 $bar 中引用 $foo 的引用计数不会因为父对象 $foo 被释放而递减,这时PHP认为你仍需要 $foo 对
象,也就不会释放这部分的内存……大概是这样。
这里确实可以看出我的无知,但大体意思是:一个引用计数没有递减,所以一些内存永远得不到释放。
在前面提到的 bugs.php.net 链接中我看到修改垃圾回收的过程将会牺牲极大的性能,因为我对引用计数
了解不多,所以我认为这是真的。
与其改变垃圾回收的过程,为什么不用 unset() 对内部对象做释放的工作呢?(或者在释放对象的时候
调用 __destruct()?)
也许PHP内核开发者可以在此或其他地方,对这种垃圾回收处理机制做出修改。
更新:Martin Fjordvald 在评论中提到了一个由 David Wang 为垃圾回收所写的补丁(其实它看起来更
像“一整块布”——非常巨大。详情参见此邮件结尾的CVS导出信息。)确实存在(一封邮件),并受到
了PHP内核开发成员的关注。问题是这个补丁要不要放到PHP5.3中并未得到太多支持。我觉得一个不错的
折中方案就是在 unset() 函数中调用对象中的 __destruct() 方法;
========================内存溢出解决方案
在做数据统计分析时,经常会遇到大数组,可能会发生内存溢出,这里分享一下我的解决方案。还是用例子来说明这个问题,如下:
假定日志中存放的记录数为500000条,那么解决方案如下:
ini_set(‘memory_limit’,’64M’); //重置php可以使用的内存大小为64M,一般在远程主机上是不能修改php.ini文件的,只能通过程序设置。注:在safe_mode(安全模式)下,ini_set失效
set_time_limit(600);//设置超时限制为6分钟
$farr = $Uarr = $Marr = $IParr = $data = $_sub = array();
$spt = ”$@#!$”;
$root = ”/Data/webapps/VisitLog”;
$path = $dpath = $fpath = NULL;
$path = $root.”/”.date(“Y-m”,$timestamp);
$dpath = $path.”/”.date(“m-d”,$timestamp);
for($j=0;$j<24;$j++){
$v = ($j < 10) ? ”0″.$j : $j;
$gpath = $dpath.”/”.$v.”.php”;
if(!file_exists($gpath)){
continue;
} else {
$arr = file($gpath);////将文件读入数组中
array_shift($arr);//移出第一个单元-》<?php exit;?>
$farr = array_merge($farr,$arr);
unset($arr);
}
}
if(empty($this->farr)){
echo ”<p><center>没有相关记录!</center></p>”;
exit;
}
while(!empty($farr)){
$_sub = array_splice($farr, 0, 10000); //每次取出$farr中1000个
for($i=0,$scount=count($_sub);$i<$scount;$i++){
$arr = explode($spt,$_sub[$i]);
$Uarr[] = $arr[1]; //vurl
$Marr[] = $arr[2]; //vmark
$IParr[] = $arr[3].” |$nbsp;”.$arr[1]; //IP
}
unset($_sub);//用完及时销毁
}
unset($farr);
这里,不难看出,一方面,我们要增加PHP可用内存大小,另一方面,只要我们想办法对数组进行分批处理,分而治之,将用过的变量及时销毁(unset),一般是不会出现溢出问题的。
另外,为了节省PHP程序内存损耗,我们应当尽可能减少静态变量的使用,在需要数据重用时,可以考虑使用引用(&)。再一点就是:数据库操作完成后,要马上关闭连接;一个对象使用完,要及时调用析构函数(__destruct())。
============================unset销毁变量并释放内存问题
PHP的unset()函数用来清除、销毁变量,不用的变量,我们可以用unset()将它销毁。但是某些时候,用unset()却无法达到销毁变 量占用的内存!我们先看一个例子:
<?php
$s=str_repeat('1',255); //产生由255个1组成的字符串
$m=memory_get_usage(); //获取当前占用内存
unset($s);
$mm=memory_get_usage(); //unset()后再查看当前占用内存
echo $m-$mm;
?>
最后输出unset()之前占用内存减去unset()之后占用内存,如果是正数,那么说明unset($s)已经将$s从内存中销毁(或者说,unset()之后内存占用减少了),可是我在PHP5和windows平台下,得到的结果是:0。这是否可以说明,unset($s)并没有起 到销毁变量$s所占用内存的作用呢?我们再作下面的例子:
<?php
$s=str_repeat('1',256); //产生由256个1组成的字符串
$m=memory_get_usage(); //获取当前占用内存
unset($s);
$mm=memory_get_usage(); //unset()后再查看当前占用内存
echo $m-$mm;
?>
这个例子,和上面的例子几乎相同,唯一的不同是,$s由256个1组成,即比第一个例子多了一个1,得到结果是:272。这是否可以说 明,unset($s)已经将$s所占用的内存销毁了?
通过上面两个例子,我们可以得出以下结论:
结论一、unset()函数只能在变量值占用内存空间超过256字节时才会释放内存空间。
那么是不是只要变量值超过256,使用unset就可以释放内存空间呢?我们再通过一个例子来测试一下:
<?php
$s=str_repeat('1',256); //这和第二个例子完全相同
$p=&$s;
$m=memory_get_usage();
unset($s); //销毁$s
$mm=memory_get_usage();
echo $p.'<br />';
echo $m-$mm;
?>
刷新页面,我们看到第一行有256个1,第二行是0,按理说我们已经销毁了$s,而$p只是引用$s的变量,应该是没有内容了,另 外,unset($s)前后内存占用没变化!现在我们再做以下的例子:
<?php
$s=str_repeat('1',256); //这和第二个例子完全相同
$p=&$s;
$m=memory_get_usage();
$s=null; //设置$s为null
$mm=memory_get_usage();
echo $p.'<br />';
echo $m-$mm;
?>
现在刷新页面,我们看到,输出$p已经是没有内容了,unset()前后内存占用量之差是272,即已经清除了变量占用的内存。本例中的$s=null也 可以换成unset(),如下:
<?php
$s=str_repeat('1',256); //这和第二个例子完全相同
$p=&$s;
$m=memory_get_usage();
unset($s); //销毁$s
unset($p);
$mm=memory_get_usage();
echo $p.'<br />';
echo $m-$mm;
?>
我们将$s和$p都使用unset()销毁,这时再看内存占用量之差也是272,说明这样也可以释放内存。那么,我们可以得到另外一条结论:
结论二、只有当指向该变量的所有变量(如引用变量)都被销毁后,才会释放内存。
来自:http://zhengdl126.iteye.com/blog/1112231
解决WordPress 2MB的上传文件大小的限制
Php/Js/Shell/Go jackxiang 2013-8-10 14:47
当我们在使用Wordpress写文章,然后上传一些图片,或者别的文件到媒体库的时候,左下角的“上传文件大小限制:2MB“就直接打击了那些胖子们。如何修改2MB的上传大小限制呢?
PS:有些主机商在后台已经严格限制了上传大小为2MB,Cpanel的用户可以在后台控制面板里的”PHP设置“里查看到,如下图:
9ac2243agw1dvjlffkdvtj 如何修改Wordpress 2MB的上传限制
不过你可以使用FTP来上传图片、音频到Wordpress的媒体库。不过有些主机上还是能修改上传大小的限制的。
方法一:可能不行:http://jackxiang.com/post/6572/
在functions.php中添加如下代码,这样上传限制就是64M:
@ini_set( 'upload_max_size' , '64M' );
@ini_set( 'post_max_size', '64M');
@ini_set( 'max_execution_time', '300' );
方法二:这个没试过,应该是不行的。
在你的主机空间的根目录新建一个php.ini文件,然后复制以下代码:
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 300
方法三:这个可行,参考:http://jackxiang.com/post/6572/
使用.htaccess文件,在这个文件中添加如下代码:
php_value upload_max_filesize 64M
php_value post_max_size 64M
php_value max_execution_time 300
php_value max_input_time 300
来自:http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece763105392230e54f73c678b854b2c88c65f93130716017bb0fb76784b408484616305a85d19b7b0607d725e60e1d988df0b9cac925938fe2223076b914062c469a9dc3224d621e04d98a40e96cee74295b9a1a3c85523dd22726df1f69c2a7103be18e71541f4d69f5f615e07ccef2716fc4e7659882233a14689e06d3e&p=8b2a972986cc41af52adca1258408b&newp=882a9545dc9e1df310be9b7c5807c4231610db2151ddd5152288cf00&user=baidu&fm=sc&query=Wordpress+%D7%EE%B4%F3%C9%CF%B4%AB%CE%C4%BC%FE%B4%F3%D0%A1%3A2MB&qid=&p1=1
PS:有些主机商在后台已经严格限制了上传大小为2MB,Cpanel的用户可以在后台控制面板里的”PHP设置“里查看到,如下图:
9ac2243agw1dvjlffkdvtj 如何修改Wordpress 2MB的上传限制
不过你可以使用FTP来上传图片、音频到Wordpress的媒体库。不过有些主机上还是能修改上传大小的限制的。
方法一:可能不行:http://jackxiang.com/post/6572/
在functions.php中添加如下代码,这样上传限制就是64M:
@ini_set( 'upload_max_size' , '64M' );
@ini_set( 'post_max_size', '64M');
@ini_set( 'max_execution_time', '300' );
方法二:这个没试过,应该是不行的。
在你的主机空间的根目录新建一个php.ini文件,然后复制以下代码:
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 300
方法三:这个可行,参考:http://jackxiang.com/post/6572/
使用.htaccess文件,在这个文件中添加如下代码:
php_value upload_max_filesize 64M
php_value post_max_size 64M
php_value max_execution_time 300
php_value max_input_time 300
来自:http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece763105392230e54f73c678b854b2c88c65f93130716017bb0fb76784b408484616305a85d19b7b0607d725e60e1d988df0b9cac925938fe2223076b914062c469a9dc3224d621e04d98a40e96cee74295b9a1a3c85523dd22726df1f69c2a7103be18e71541f4d69f5f615e07ccef2716fc4e7659882233a14689e06d3e&p=8b2a972986cc41af52adca1258408b&newp=882a9545dc9e1df310be9b7c5807c4231610db2151ddd5152288cf00&user=baidu&fm=sc&query=Wordpress+%D7%EE%B4%F3%C9%CF%B4%AB%CE%C4%BC%FE%B4%F3%D0%A1%3A2MB&qid=&p1=1
php ini_set更改php.ini配置,通过它修改php.in达到php上传文件大小限制是不行的,除非修改.htaccess文件。
Php/Js/Shell/Go jackxiang 2013-8-9 15:59
用该参数可以自行设置 php.ini 文件中设置变量的值,其语法为:
-d configuration_directive[=value]
Egg容器启动es: /usr/local/php/bin/php -d EASYSWOOLE_ROOT=/data/www /data/www/easyswoole start dev
来自:https://www.cnblogs.com/myjavawork/articles/1869205.html
php.ini里有的变量才能修改,没有的变量返回false:
PHP ini_set() 无效的原因:
如题:我租的是虚拟主机,php.ini里的upload_max_filesize是默认的2M,要直接修改php.ini文件是不可能的。我如果想上传超过2M的怎么呢?ini_set("upload_max_filesize", "8M");我试了,好象没有用!!
ini_set("upload_max_filesize", "8M");肯定不能用啊,要是随便一个用户都能修改的话,那这个虚拟主机上的其他用户不倒霉了?!!
我改过php.ini中的upload_max_filesize 有效。(假的)
========================================================================================================
ini_set,post_max_size,upload_max_filesize,magic_quotes_gpc等用ini_set设置不了!
ini_set('max_execution_time','10′);
ini_set('memory_limit','1024M');
echo 'max_execution_time = ' . ini_get('max_execution_time') . "";
echo 'memory_limit = ' . ini_get('memory_limit') . "";
echo 'post_max_size = ' . ini_get('post_max_size') . "";
echo 'upload_max_filesize = ' . ini_get('upload_max_filesize') . "";
ini_set('max_execution_time','10′);
ini_set('memory_limit','1024M');
注意:
post_max_size,upload_max_filesize用下面的方法是修改不了的.
ini_set('post_max_size','1024M');
ini_set('upload_max_filesize','1024M');
正确做法是用.htaccess文件:
php_value upload_max_filesize "80M"
php_value post_max_size "80M"
php_value max_execution_time "2000"
php_value memory_limit "150M"
补充知识点:
其实在php文档里有说明upload_max_filesize的可修改范围是PHP_INI_PERDIR。
PHP_INI_PERDIR的意思是域内指令可以在php.ini、httpd.conf或.htaccess文件中修改。
PHP_INI_SYSTEM 域内指令可以在php.ini和httpd.conf文件中修改
所以upload_max_filesize用int_set是无法修改的。只有可修改范围是PHP_INI_ALL的才可以用int_set修改。
Nginx,上传:通过设置nginx的client_max_body_size解决nginx+php上传大文件的问题
http://hi.baidu.com/zhizheqianlv/item/d5989d506b1f6f15aaf6d702
client_max_body_size
这个可以限制
magic_quotes_gpc 用 get_magic_quotes_gpc() 获得,不能用 set_magic_quotes_gpc 修改,原因是没这个函数。而magic_quotes_runtime可以用set_magic_quotes_runtime()来设置
http://www.111cn.net/phper/php-function/34292.htm
阅读全文
-d configuration_directive[=value]
Egg容器启动es: /usr/local/php/bin/php -d EASYSWOOLE_ROOT=/data/www /data/www/easyswoole start dev
来自:https://www.cnblogs.com/myjavawork/articles/1869205.html
php.ini里有的变量才能修改,没有的变量返回false:
PHP ini_set() 无效的原因:
如题:我租的是虚拟主机,php.ini里的upload_max_filesize是默认的2M,要直接修改php.ini文件是不可能的。我如果想上传超过2M的怎么呢?ini_set("upload_max_filesize", "8M");我试了,好象没有用!!
ini_set("upload_max_filesize", "8M");肯定不能用啊,要是随便一个用户都能修改的话,那这个虚拟主机上的其他用户不倒霉了?!!
我改过php.ini中的upload_max_filesize 有效。(假的)
========================================================================================================
ini_set,post_max_size,upload_max_filesize,magic_quotes_gpc等用ini_set设置不了!
ini_set('max_execution_time','10′);
ini_set('memory_limit','1024M');
echo 'max_execution_time = ' . ini_get('max_execution_time') . "";
echo 'memory_limit = ' . ini_get('memory_limit') . "";
echo 'post_max_size = ' . ini_get('post_max_size') . "";
echo 'upload_max_filesize = ' . ini_get('upload_max_filesize') . "";
ini_set('max_execution_time','10′);
ini_set('memory_limit','1024M');
注意:
post_max_size,upload_max_filesize用下面的方法是修改不了的.
ini_set('post_max_size','1024M');
ini_set('upload_max_filesize','1024M');
正确做法是用.htaccess文件:
php_value upload_max_filesize "80M"
php_value post_max_size "80M"
php_value max_execution_time "2000"
php_value memory_limit "150M"
补充知识点:
其实在php文档里有说明upload_max_filesize的可修改范围是PHP_INI_PERDIR。
PHP_INI_PERDIR的意思是域内指令可以在php.ini、httpd.conf或.htaccess文件中修改。
PHP_INI_SYSTEM 域内指令可以在php.ini和httpd.conf文件中修改
所以upload_max_filesize用int_set是无法修改的。只有可修改范围是PHP_INI_ALL的才可以用int_set修改。
Nginx,上传:通过设置nginx的client_max_body_size解决nginx+php上传大文件的问题
http://hi.baidu.com/zhizheqianlv/item/d5989d506b1f6f15aaf6d702
client_max_body_size
这个可以限制
magic_quotes_gpc 用 get_magic_quotes_gpc() 获得,不能用 set_magic_quotes_gpc 修改,原因是没这个函数。而magic_quotes_runtime可以用set_magic_quotes_runtime()来设置
http://www.111cn.net/phper/php-function/34292.htm
阅读全文
Linux查看文件句柄占用多的进程 ,查看Linux某进程的句柄数,并通过ulimit -n 单个进程打开的最大文件句柄数量限制解决accept4() failed (24: Too many open files)
Unix/LinuxC技术 jackxiang 2013-8-8 14:49
查看当前进程的最大可以打开的文件数:
cat /proc/PID/limits (如果通过ulimit -n 设置或者修改/etc/security/limits.conf,看看进程是否生效)
ulimit -a|grep "open files"
open files (-n) 1024000
直接对文件的修改如下:
cat /etc/security/limits.conf|grep -Ei 'soft|hard'
* soft nofile 1024000
* hard nofile 1024000
* soft nproc 1024000
* hard nproc 1024000
cat /proc/1279/limits |grep files
Max open files 8192 8192 files
cat /proc/64658/limits |grep files
Max open files 1024000 1024000 files
cat /proc/64658/limits |grep files
cat /proc/18576/limits |grep files
Max open files 1024000 1024000 files
怎么修改?
# CentOS7系统使用命令
prlimit --nofile=65536:65536 --pid 39977
# CentOS6系统使用命令
echo - n "Max open files=65535:65535" > /proc/39977/limits
当然,可以通过重启这个进程所对应的服务(如果可重启,也不会来修改这个session里的参数了)来重新读取系统里的默认设置。
ulimit -n
# 临时修改,重启失效
ulimit -HSn 65536
# 永久解决
vim /etc/security/limits.conf
# 添加如下的行
* soft nproc 65536
* hard nproc 65536
* soft nofile 65536
* hard nofile 65536
实践如下:
原文链接:https://blog.csdn.net/dqchouyang/article/details/115230076
Linux查看文件句柄占用多的进程 :
其中第一列是打开的句柄数,第二列是进程ID。
可以根据ID号来查看进程名和进程的句柄详细情况:
8798 8770 8797 8770 8769 8764 8763 8713 8618 均是PHP的PHP-FPM的句柄数,也就是说第一是virtualBOX,再才是certmonger服务,后是clock-applet,再后是php-fpm进程,这些进程文件数分布排列很正常~
(1)这个没啥用就关了得了:
certmonger 0:关闭 1:关闭 2:关闭 3:关闭 4:关闭 5:关闭 6:关闭
chkconfig certmonger off
root@119.10.6.54:~# chkconfig certmonger off
root@119.10.6.54:~# chkconfig --list|grep certmonger
certmonger 0:关闭 1:关闭 2:关闭 3:关闭 4:关闭 5:关闭 6:关闭
root@119.10.6.54:~# service certmonger stop
停止 certmonger: [确定]
重启后按Esc或者F5键,可以查看系统启动过程,卡在哪里,我的是在certmonger启动OK之后卡住的,完全有必要停掉,来源:
http://www.linuxidc.com/Linux/2015-02/112688.htm
(2)/usr/libexec/clock-applet --oaf-activate-iid=OAFIID:GNOME_ClockApplet_Factory --oaf-ior-fd=29
这个好像是gnome的时间同步啥的一个服务,暂时不关。
(1)查看Linux系统默认的最大文件句柄数,系统默认是1024
(3)对服务器没有用的也关了,调节cpu速度用来省电,常用在Laptop上:
service cpuspeed stop
chkconfig cpuspeed off
——————————————————————————————————————————————————
ulimit -n
1024
(2)查看当前进程打开了多少句柄数
lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr|more
131 24204
57 24244
57 24231 ........
其中第一列是打开的句柄数,第二列是进程ID。
(3)可以根据ID号来查看进程名。
ps aef|grep 24204
nginx 24204 24162 99 16:15 ? 00:24:25 /usr/local/nginx/sbin/nginx -s
来自:http://www.examw.com/linux/all/146041/
accept4() failed (24: Too many open files)
如何优化这个
ulimit -n 是多少?
文件描述符不够用了
1024
这个可以开大点
能开多大,如何去衡量啊
内存足够都可以
一般开10万
好的,我看看。
来源:PHP高级编程QQ对话。
=========================================
实践如何找到当面数据库打开了多少个文件句柄数的如下实践:
1)先PS一下获取到Mysql的进程号:
root 4935 0.0 0.0 63992 272 ? S Aug06 0:00 /bin/sh /usr/local/mysql/bin/mysqld_safe --defaults-file=/usr/local/mysql/conf/my.cnf
mysql 5622 4.5 83.4 14974096 6823984 ? Sl Aug06 149:07 /usr/local/mysql/bin/mysqld --defaults-file=/usr/local/mysql/conf/my.cnf --basedir=/usr/local/mysql --datadir=/data/db/mysql --plugin-dir=/usr/local/mysql/lib/plugin --user=mysql --log-error=/data/db/mysql/localhost.localdomain.err --open-files-limit=65535 --pid-file=/data/db/mysql/localhost.localdomain.pid --socket=/tmp/mysqld.sock --port=3306
2)得到如下两个进程号:
4935
5622
3)通过lsof获取到所有进程的句柄数再grep一下就得到了当前mysql的进程为4935的句柄数:
/usr/sbin/lsof -n|awk '{print $2}'|sort|uniq -c |sort -nr|grep 4935
4 4935
4)一样的方法:
/usr/sbin/lsof -n|awk '{print $2}'|sort|uniq -c |sort -nr|grep 5622
4 5622
目前只打开了4个文件句柄数量,远远底于系统默认值1024。
=========================================
在系统访问高峰时间以root用户执行上面的脚本,可能出现的结果如下:
# lsof -n|awk '{print $2}'|sort|uniq -c |sort -nr|more
131 24204
57 24244
57 24231
56 24264
其中第一行是打开的文件句柄数量,第二行是进程号。得到进程号后,我们可以通过ps命令得到进程的详细内容。
ps -aef|grep 24204
mysql 24204 24162 99 16:15 ? 00:24:25 /usr/sbin/mysqld
哦,原来是mysql进程打开最多文件句柄数量。但是他目前只打开了131个文件句柄数量,远远底于系统默认值1024。
但是如果系统并发特别大,尤其是squid服务器,很有可能会超过1024。这时候就必须要调整系统参数,以适应应用变化。Linux有硬性限制和软性限制。可以通过ulimit来设定这两个参数。方法如下,以root用户运行以下命令:
ulimit -HSn 4096
以上命令中,H指定了硬性大小,S指定了软性大小,n表示设定单个进程最大的打开文件句柄数量。个人觉得最好不要超过4096,毕竟打开的文件句柄数越多响应时间肯定会越慢。设定句柄数量后,系统重启后,又会恢复默认值。如果想永久保存下来,可以修改.bash_profile文件,可以修改 /etc/profile 把上面命令加到最后。
用普通用户登录,执行ulimit -n,查看文件打开数。
如果太小,默认值是1024,则进行如下操作:
使用root用户修改vim /etc/security/limits.conf 文件。
在文件最后加如下两句话:
* soft nofile 50000
* hard nofile 50000
参考:http://hi.baidu.com/itnote/item/7347bfea829e3ee3fa42bad8
cat /proc/PID/limits (如果通过ulimit -n 设置或者修改/etc/security/limits.conf,看看进程是否生效)
ulimit -a|grep "open files"
open files (-n) 1024000
直接对文件的修改如下:
cat /etc/security/limits.conf|grep -Ei 'soft|hard'
* soft nofile 1024000
* hard nofile 1024000
* soft nproc 1024000
* hard nproc 1024000
cat /proc/1279/limits |grep files
Max open files 8192 8192 files
cat /proc/64658/limits |grep files
Max open files 1024000 1024000 files
cat /proc/64658/limits |grep files
cat /proc/18576/limits |grep files
Max open files 1024000 1024000 files
怎么修改?
# CentOS7系统使用命令
prlimit --nofile=65536:65536 --pid 39977
# CentOS6系统使用命令
echo - n "Max open files=65535:65535" > /proc/39977/limits
当然,可以通过重启这个进程所对应的服务(如果可重启,也不会来修改这个session里的参数了)来重新读取系统里的默认设置。
ulimit -n
# 临时修改,重启失效
ulimit -HSn 65536
# 永久解决
vim /etc/security/limits.conf
# 添加如下的行
* soft nproc 65536
* hard nproc 65536
* soft nofile 65536
* hard nofile 65536
实践如下:
原文链接:https://blog.csdn.net/dqchouyang/article/details/115230076
Linux查看文件句柄占用多的进程 :
其中第一列是打开的句柄数,第二列是进程ID。
可以根据ID号来查看进程名和进程的句柄详细情况:
8798 8770 8797 8770 8769 8764 8763 8713 8618 均是PHP的PHP-FPM的句柄数,也就是说第一是virtualBOX,再才是certmonger服务,后是clock-applet,再后是php-fpm进程,这些进程文件数分布排列很正常~
(1)这个没啥用就关了得了:
certmonger 0:关闭 1:关闭 2:关闭 3:关闭 4:关闭 5:关闭 6:关闭
chkconfig certmonger off
root@119.10.6.54:~# chkconfig certmonger off
root@119.10.6.54:~# chkconfig --list|grep certmonger
certmonger 0:关闭 1:关闭 2:关闭 3:关闭 4:关闭 5:关闭 6:关闭
root@119.10.6.54:~# service certmonger stop
停止 certmonger: [确定]
重启后按Esc或者F5键,可以查看系统启动过程,卡在哪里,我的是在certmonger启动OK之后卡住的,完全有必要停掉,来源:
http://www.linuxidc.com/Linux/2015-02/112688.htm
(2)/usr/libexec/clock-applet --oaf-activate-iid=OAFIID:GNOME_ClockApplet_Factory --oaf-ior-fd=29
这个好像是gnome的时间同步啥的一个服务,暂时不关。
(1)查看Linux系统默认的最大文件句柄数,系统默认是1024
(3)对服务器没有用的也关了,调节cpu速度用来省电,常用在Laptop上:
service cpuspeed stop
chkconfig cpuspeed off
——————————————————————————————————————————————————
ulimit -n
1024
(2)查看当前进程打开了多少句柄数
lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr|more
131 24204
57 24244
57 24231 ........
其中第一列是打开的句柄数,第二列是进程ID。
(3)可以根据ID号来查看进程名。
ps aef|grep 24204
nginx 24204 24162 99 16:15 ? 00:24:25 /usr/local/nginx/sbin/nginx -s
来自:http://www.examw.com/linux/all/146041/
accept4() failed (24: Too many open files)
如何优化这个
ulimit -n 是多少?
文件描述符不够用了
1024
这个可以开大点
能开多大,如何去衡量啊
内存足够都可以
一般开10万
好的,我看看。
来源:PHP高级编程QQ对话。
=========================================
实践如何找到当面数据库打开了多少个文件句柄数的如下实践:
1)先PS一下获取到Mysql的进程号:
root 4935 0.0 0.0 63992 272 ? S Aug06 0:00 /bin/sh /usr/local/mysql/bin/mysqld_safe --defaults-file=/usr/local/mysql/conf/my.cnf
mysql 5622 4.5 83.4 14974096 6823984 ? Sl Aug06 149:07 /usr/local/mysql/bin/mysqld --defaults-file=/usr/local/mysql/conf/my.cnf --basedir=/usr/local/mysql --datadir=/data/db/mysql --plugin-dir=/usr/local/mysql/lib/plugin --user=mysql --log-error=/data/db/mysql/localhost.localdomain.err --open-files-limit=65535 --pid-file=/data/db/mysql/localhost.localdomain.pid --socket=/tmp/mysqld.sock --port=3306
2)得到如下两个进程号:
4935
5622
3)通过lsof获取到所有进程的句柄数再grep一下就得到了当前mysql的进程为4935的句柄数:
/usr/sbin/lsof -n|awk '{print $2}'|sort|uniq -c |sort -nr|grep 4935
4 4935
4)一样的方法:
/usr/sbin/lsof -n|awk '{print $2}'|sort|uniq -c |sort -nr|grep 5622
4 5622
目前只打开了4个文件句柄数量,远远底于系统默认值1024。
=========================================
在系统访问高峰时间以root用户执行上面的脚本,可能出现的结果如下:
# lsof -n|awk '{print $2}'|sort|uniq -c |sort -nr|more
131 24204
57 24244
57 24231
56 24264
其中第一行是打开的文件句柄数量,第二行是进程号。得到进程号后,我们可以通过ps命令得到进程的详细内容。
ps -aef|grep 24204
mysql 24204 24162 99 16:15 ? 00:24:25 /usr/sbin/mysqld
哦,原来是mysql进程打开最多文件句柄数量。但是他目前只打开了131个文件句柄数量,远远底于系统默认值1024。
但是如果系统并发特别大,尤其是squid服务器,很有可能会超过1024。这时候就必须要调整系统参数,以适应应用变化。Linux有硬性限制和软性限制。可以通过ulimit来设定这两个参数。方法如下,以root用户运行以下命令:
ulimit -HSn 4096
以上命令中,H指定了硬性大小,S指定了软性大小,n表示设定单个进程最大的打开文件句柄数量。个人觉得最好不要超过4096,毕竟打开的文件句柄数越多响应时间肯定会越慢。设定句柄数量后,系统重启后,又会恢复默认值。如果想永久保存下来,可以修改.bash_profile文件,可以修改 /etc/profile 把上面命令加到最后。
用普通用户登录,执行ulimit -n,查看文件打开数。
如果太小,默认值是1024,则进行如下操作:
使用root用户修改vim /etc/security/limits.conf 文件。
在文件最后加如下两句话:
* soft nofile 50000
* hard nofile 50000
参考:http://hi.baidu.com/itnote/item/7347bfea829e3ee3fa42bad8
背景:个人认为Wordpress优势在于它的移动互联网功能及其跨终端的功能,如:APP,Ipad,Android都有,而且开源。
阅读全文
阅读全文
js扫描系统进程 查看注册表实现。
Php/Js/Shell/Go jackxiang 2013-8-2 17:50
背景:一些浏览器的其它协议,如自定义协议,会扫描进程的列表,及通过js读注册表(客户端会写注册表,以达到判断是否安装过客户端)等,是必须用到的。
JS操作本地注册表有很多限制,默认浏览器是没有打开JS本地脚本操作的,如果浏览器没有配置且安全级别比较高,或者杀毒和防木马软件,直接用JS操作注册表会被阻止的,为了保险期间实现这个功能“需要在登陆后先判断是否安装过客户端才能进行游戏”,最好的方式个人认为是,通过客户端实现一个浏览器的插件,然后在JS中判断插件是否已经安装,然后通过插件启动客户端或做其他的事情比较稳妥。
一般这样做,我估计百度影音通过网络浏览器到播放器(好在没有广告)就是这么干的,好使用HTA(HTML application),不然通过Web访问会出现安全提示。:
干脆在客户端游戏安装过程中,同时安装一个BHO,好处是JS可以直接调用activex判断是否安装了,而且可以通过activex直接启动客户端,并且可以把用户的登录状成直接带到客户端游戏去,省得重新输密码登录。
读取注册表的办法,比较简单
<script language="JScript">
var WshShell = new ActiveXObject("WScript.Shell");
keyValue = WshShell.RegRead("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Paths\\Directory");
alert(keyValue);
</script>
原则上,只要注册表记录的信息都可以查到。
但系统进程是在内存中,而不是在注册表也不是在硬盘上,可以使用win32 API CreateToolhelp32Snapshot 扫描系统进程,js不借助ActiveX是做不到的。
用WSH可以做很多的事...
我实践了是可以hta来读取注册表和执行程序的,找开获得23.0,打开了cmd,如下:
如果用浏览器去执行这个会出现,如下问题,也就是说浏览器想要执行EXE可执行程序得要通过ActiveX控件去做,实践如下:
http://localhost/jsReg.html
ReferenceError: ActiveXObject is not defined
[在此错误处中断]
var WSH = new ActiveXObject("WScript.Shell");
jsReg.html (第 22 行)
ReferenceError: ActiveXObject is not defined
[在此错误处中断]
var obj = new ActiveXObject("WScript.Shell");
参考来自:
http://www.itlead.com.cn/article/html/148/2011-07-26/content-1027.shtml
var wsh=new ActiveXObject("WScript.Shell");
wsh.AppActive("title");//激活指定title的应用程序窗口
wsh.CreateShortcut();//建立快捷方式
wsh.Popup();//提示
wsh.RegDelete();//删除注册表项
wsh.RegRead();//读取注册表
wsh.RegWrite();//写注册表
wsh.Run("c:\\test.exe");//运行程序
wsh.SendKeys();//摸拟按键
//...........
等等一堆
你想要做系统进程扫描的话,可以使用WMI对象来...
呵呵,并不是像大花猫说的,JS还是可以做的...
http://www.microsoft.com/china/MSDN/library/enterprisedevelopment/softwaredev/WDdnclinicscripting.mspx
这是MS上的WMI的参考文档...
你想像一下msinfo32.exe可以做什么事,可以查看到什么系统信息,你用JS使用WMI也能做什么,但是前提是你的WMI服务要启动地哦,不过默认是启动地...
http://www.microsoft.com/china/technet/community/scriptcenter/resources/wmifaq.mspx
WMI的秘密
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/wmi_reference.asp
WMI参考文档。。。
你一定要去看看。。
里面的示便都是用VBS做的,你自己用JS当然也一样能行。。。
来源:http://bbs.csdn.net/topics/80029089
参考:http://www.dewen.org/q/663
http://blog.csdn.net/yu555666/article/details/1563547
JS操作本地注册表有很多限制,默认浏览器是没有打开JS本地脚本操作的,如果浏览器没有配置且安全级别比较高,或者杀毒和防木马软件,直接用JS操作注册表会被阻止的,为了保险期间实现这个功能“需要在登陆后先判断是否安装过客户端才能进行游戏”,最好的方式个人认为是,通过客户端实现一个浏览器的插件,然后在JS中判断插件是否已经安装,然后通过插件启动客户端或做其他的事情比较稳妥。
一般这样做,我估计百度影音通过网络浏览器到播放器(好在没有广告)就是这么干的,好使用HTA(HTML application),不然通过Web访问会出现安全提示。:
干脆在客户端游戏安装过程中,同时安装一个BHO,好处是JS可以直接调用activex判断是否安装了,而且可以通过activex直接启动客户端,并且可以把用户的登录状成直接带到客户端游戏去,省得重新输密码登录。
读取注册表的办法,比较简单
<script language="JScript">
var WshShell = new ActiveXObject("WScript.Shell");
keyValue = WshShell.RegRead("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Paths\\Directory");
alert(keyValue);
</script>
原则上,只要注册表记录的信息都可以查到。
但系统进程是在内存中,而不是在注册表也不是在硬盘上,可以使用win32 API CreateToolhelp32Snapshot 扫描系统进程,js不借助ActiveX是做不到的。
用WSH可以做很多的事...
我实践了是可以hta来读取注册表和执行程序的,找开获得23.0,打开了cmd,如下:
如果用浏览器去执行这个会出现,如下问题,也就是说浏览器想要执行EXE可执行程序得要通过ActiveX控件去做,实践如下:
http://localhost/jsReg.html
ReferenceError: ActiveXObject is not defined
[在此错误处中断]
var WSH = new ActiveXObject("WScript.Shell");
jsReg.html (第 22 行)
ReferenceError: ActiveXObject is not defined
[在此错误处中断]
var obj = new ActiveXObject("WScript.Shell");
参考来自:
http://www.itlead.com.cn/article/html/148/2011-07-26/content-1027.shtml
var wsh=new ActiveXObject("WScript.Shell");
wsh.AppActive("title");//激活指定title的应用程序窗口
wsh.CreateShortcut();//建立快捷方式
wsh.Popup();//提示
wsh.RegDelete();//删除注册表项
wsh.RegRead();//读取注册表
wsh.RegWrite();//写注册表
wsh.Run("c:\\test.exe");//运行程序
wsh.SendKeys();//摸拟按键
//...........
等等一堆
你想要做系统进程扫描的话,可以使用WMI对象来...
呵呵,并不是像大花猫说的,JS还是可以做的...
http://www.microsoft.com/china/MSDN/library/enterprisedevelopment/softwaredev/WDdnclinicscripting.mspx
这是MS上的WMI的参考文档...
你想像一下msinfo32.exe可以做什么事,可以查看到什么系统信息,你用JS使用WMI也能做什么,但是前提是你的WMI服务要启动地哦,不过默认是启动地...
http://www.microsoft.com/china/technet/community/scriptcenter/resources/wmifaq.mspx
WMI的秘密
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/wmi_reference.asp
WMI参考文档。。。
你一定要去看看。。
里面的示便都是用VBS做的,你自己用JS当然也一样能行。。。
来源:http://bbs.csdn.net/topics/80029089
参考:http://www.dewen.org/q/663
http://blog.csdn.net/yu555666/article/details/1563547
[编码问题]php自动获取字符串编码函数mb_detect_encoding
Php/Js/Shell/Go jackxiang 2013-7-31 13:23
背景:有外包兄弟说是编码上有问题,于是从编码上想判断一下到底是什么编码,用了这个函数去判断。我倒是喜欢直接用editplus去另存为就知道文件编码,不知这样是不是100%准呢?呵呵。
使用 mb_detect_encoding() 函数来判断字符串是什么编码的。
当在php中使用mb_detect_encoding函数进行编码识别时,很多人都碰到过识别编码有误的问题,例如对与GB2312和UTF- 8,或者UTF-8和GBK(这里主要是对于cp936的判断),网上说是由于字符短是,mb_detect_encoding会出现误判。
例如,代码如下:
$encode = mb_detect_encoding($keytitle, array("ASCII",'UTF-8′,"GB2312′,"GBK",'BIG5′));
if ($encode == “UTF-8″){
$keytitle = iconv("UTF-8″,"GBK",$keytitle);
}
这段代码的作用是检测字符串的编码是否UTF-8,是的话就转换为GBK。
可是当 $keytitle = “%D0%BE%C6%AC”;时。检测结果却是UTF-8.这个bug其实不算是bug,写程序时也不应当过于依赖mb_detect_encoding,当字符串较短时,检测结果产生偏差的可能性很大。
怎么解决呢,我的办法是:
复制代码 代码如下:
$encode = mb_detect_encoding($keytitle, array('ASCII','GB2312′,'GBK','UTF-8');
三个参数分别是:被检测的输入变量、编码方式的检测顺序(一旦为真,后面自动忽略)、strict模式
对编码检测的顺序进行调整,将最大可能性放在前面,这样减少被错误转换的机会。
一般要先排gb2312,当有GBK和UTF-8时,需要将常用的排列到前面。
来自:http://www.jb51.net/article/27282.htm
使用 mb_detect_encoding() 函数来判断字符串是什么编码的。
当在php中使用mb_detect_encoding函数进行编码识别时,很多人都碰到过识别编码有误的问题,例如对与GB2312和UTF- 8,或者UTF-8和GBK(这里主要是对于cp936的判断),网上说是由于字符短是,mb_detect_encoding会出现误判。
例如,代码如下:
$encode = mb_detect_encoding($keytitle, array("ASCII",'UTF-8′,"GB2312′,"GBK",'BIG5′));
if ($encode == “UTF-8″){
$keytitle = iconv("UTF-8″,"GBK",$keytitle);
}
这段代码的作用是检测字符串的编码是否UTF-8,是的话就转换为GBK。
可是当 $keytitle = “%D0%BE%C6%AC”;时。检测结果却是UTF-8.这个bug其实不算是bug,写程序时也不应当过于依赖mb_detect_encoding,当字符串较短时,检测结果产生偏差的可能性很大。
怎么解决呢,我的办法是:
复制代码 代码如下:
$encode = mb_detect_encoding($keytitle, array('ASCII','GB2312′,'GBK','UTF-8');
三个参数分别是:被检测的输入变量、编码方式的检测顺序(一旦为真,后面自动忽略)、strict模式
对编码检测的顺序进行调整,将最大可能性放在前面,这样减少被错误转换的机会。
一般要先排gb2312,当有GBK和UTF-8时,需要将常用的排列到前面。
来自:http://www.jb51.net/article/27282.htm
http://windows.chinaitlab.com/server/534808_1.html
http://windows.chinaitlab.com/server/534808_2.html
http://windows.chinaitlab.com/server/534808_3.html
http://windows.chinaitlab.com/server/534808_2.html
http://windows.chinaitlab.com/server/534808_3.html
卡布奇诺手机2 移动版 16GB 大字体大喇叭中老年智能手机
背景:当今,智能机横行,老人确没法用上,抱怨有三点:
1)触摸屏幕失效,不好使,提出要有物理按钮的手机。
2)屏幕在太阳光偏强的地儿看不清楚字体,要有手捂住,于是提出要翻盖的手机(可能老人认为这样可能会更容易看到吧)。
3)屏幕字体太小,始终是个问题,看不清,于是提出:需要一个大字体的手机。
-----------------------------------------------------------------------------------------------------------------------
于是,在这样的环境下,发现一个老外在解决这个问题,而它的默认的那个theme风格,在太阳光下都能看清,经我的i9000手机测试了下还真是个好的样式,免费的有,收费的好像60来RMB吧,不是太贵。它的官网是:http://biglauncher.com/
阅读全文
背景:当今,智能机横行,老人确没法用上,抱怨有三点:
1)触摸屏幕失效,不好使,提出要有物理按钮的手机。
2)屏幕在太阳光偏强的地儿看不清楚字体,要有手捂住,于是提出要翻盖的手机(可能老人认为这样可能会更容易看到吧)。
3)屏幕字体太小,始终是个问题,看不清,于是提出:需要一个大字体的手机。
-----------------------------------------------------------------------------------------------------------------------
于是,在这样的环境下,发现一个老外在解决这个问题,而它的默认的那个theme风格,在太阳光下都能看清,经我的i9000手机测试了下还真是个好的样式,免费的有,收费的好像60来RMB吧,不是太贵。它的官网是:http://biglauncher.com/
阅读全文
夏商与西周
东周分两段
春秋和战国
一统秦两汉
三分魏楚吴
二晋前后沿
南北朝并立
隋唐五代传
宋元明清后
皇朝至此完
宋,是个古老的国名。
春秋有宋国,以其国民愚钝而出名,如守株待兔者,即以宋人名之。
东晋后又有宋国,乃东晋大将刘裕所创,领地不过江南,此时北方有少数民族的诸多国家,故史称南北朝时期。
而后又有宋者,乃唐后五代十国的最后一国,后周的大将赵匡胤所开创,史称北宋,而后被金所破,迁江南而有南宋。
是一段分裂割据时期,称之为“五代十国"。 五代十国形势图五代十国并非指一个朝代,而是指一个特殊的历史时期。五代指的是后梁、后唐、后晋、后汉、后周五个次第更迭的政权。十国指五代之外相继出现的十个割据政权:前蜀、后蜀、吴、南唐、吴越、闽、楚、南汉、南平(即荆南)、北汉,统称十国。关于五代十国的年限,一说为:北宋灭亡北汉时是公元979年,所以五代十国的历史时期为公元907年到979年。另一说为,五代十国存在于公元907年-公元960年期间。
五代十国 那是唐分裂留下的 李煜大家很熟吧 他是唐的直系皇族 也是诸侯国 然后最大的是后周 然后赵匡胤夺后周皇帝柴荣的位
你如果是指赵匡胤建立的宋的话,那它前面的大一统的王朝就是唐,唐之后是五代十国,是中国历史上比较乱的一个时代
参考:
http://zhidao.baidu.com/question/160950275.html?device=mobile&ssid=0&from=1395a&uid=C9B4D48D89528DA256CE63384166F011&pu=usm%400%2Csz%401320_1001%2Cta%40iphone_2_2.3_3_533&bd_page_type=1&tj=www_normal_1_0_10
http://zhidao.baidu.com/question/151099965.html
东周分两段
春秋和战国
一统秦两汉
三分魏楚吴
二晋前后沿
南北朝并立
隋唐五代传
宋元明清后
皇朝至此完
宋,是个古老的国名。
春秋有宋国,以其国民愚钝而出名,如守株待兔者,即以宋人名之。
东晋后又有宋国,乃东晋大将刘裕所创,领地不过江南,此时北方有少数民族的诸多国家,故史称南北朝时期。
而后又有宋者,乃唐后五代十国的最后一国,后周的大将赵匡胤所开创,史称北宋,而后被金所破,迁江南而有南宋。
是一段分裂割据时期,称之为“五代十国"。 五代十国形势图五代十国并非指一个朝代,而是指一个特殊的历史时期。五代指的是后梁、后唐、后晋、后汉、后周五个次第更迭的政权。十国指五代之外相继出现的十个割据政权:前蜀、后蜀、吴、南唐、吴越、闽、楚、南汉、南平(即荆南)、北汉,统称十国。关于五代十国的年限,一说为:北宋灭亡北汉时是公元979年,所以五代十国的历史时期为公元907年到979年。另一说为,五代十国存在于公元907年-公元960年期间。
五代十国 那是唐分裂留下的 李煜大家很熟吧 他是唐的直系皇族 也是诸侯国 然后最大的是后周 然后赵匡胤夺后周皇帝柴荣的位
你如果是指赵匡胤建立的宋的话,那它前面的大一统的王朝就是唐,唐之后是五代十国,是中国历史上比较乱的一个时代
参考:
http://zhidao.baidu.com/question/160950275.html?device=mobile&ssid=0&from=1395a&uid=C9B4D48D89528DA256CE63384166F011&pu=usm%400%2Csz%401320_1001%2Cta%40iphone_2_2.3_3_533&bd_page_type=1&tj=www_normal_1_0_10
http://zhidao.baidu.com/question/151099965.html
背景:公司里的Win7下的IE浏览器/chrome浏览器代理出现灰色,没法代理上淘宝了。
阅读全文
阅读全文