Quantcast
Channel: IT社区推荐资讯 - ITIndex.net
Viewing all 15843 articles
Browse latest View live

让你大开眼界的9款HTML5动画特效

$
0
0

前几篇文章中我们已经分享了许多令人惊叹的 HTML5 3D特效和HTML5 Canvas特效,确实非常不错,今天我们精选了9款让你大开眼界的 HTML5动画特效,一起来看看。

1、HTML5梦幻特效 可给任意元素添加魔幻效果

我们之前介绍HTML5动画特效比较多的是 HTML5 3D特效,今天我们来换一种风格,来分享一款看起来比较魔幻的HTML5特效。它可以给网页上任意元素(图片、文字等)添加这么一种效果,即鼠标滑过时,元素上就会出现非常魔幻的动画特效,什么特效呢?你可以点开demo链接查看。

html5-magic-effect

在线演示         源码下载

2、HTML5/SVG实现过山车动画

今天我们要分享一款很酷的HTML5/SVG动画,这款HTML5动画是过山车效果,主要是利用了SVG的path动画来实现的,效果非常酷。另外,关于更多SVG方面的动画,大家可以看看这款 HTML5 SVG狐狸奔跑动画HTML5/SVG实现随风摇摆的动画树,也都非常不错。

html5-svg-shanche-animation

在线演示         源码下载

3、HTML5像素粉碎图片动画 图片洒落一地

这款HTML5图片动画特效你绝对想不到,它将一张图片粉碎成许多像素颗粒,点击图片后,这些像素颗粒边掉落在地上,继续点击,粉碎的像素图片颗粒又会重新组合成完整的图片。用HTML5技术实现这种图片粉碎效果还是挺简单的,有兴趣的同学可以下载源码来学习。

html5-pixel-image-effect

在线演示         源码下载

4、HTML5 Canvas绘制灰太狼 超级可爱

HTML5 Canvas相当于一个画板,你可以在Canvas绘制任意的东西,今天要分享一款利用HTML5 Canvas绘制的灰太狼形象,个人以为,这个灰太狼绘制得十分逼真形象,小伙伴们都要惊呆了。以后我们再来弄一个HTML5 Canvas的喜洋洋如何?

html5-canvas-huitailang

在线演示         源码下载

5、用HTML5/CSS3给女朋友送个生日蛋糕

现在有了HTML5,我们在浏览器上制作动画已经不是什么难事了,但是一个好的创意却很难,比如说用技术来博得女孩子的喜欢。今天我们分享的这款生日蛋糕动画非常有创意,它是用svg来做的,利用HTML5的api让制作蛋糕的过程展示出来,这个蛋糕在妹子生日的时候送给她一定会让她觉得很惊奇。祝你成功哦!

html5-css3-new-cake

在线演示         源码下载

6、HTML5 SVG狐狸奔跑动画 相当大气

今天我要来向大家分享一款超级酷的 HTML5动画,它是一只快速奔跑的狐狸,奔跑的动作非常自然逼真,长长的狐狸尾巴也会随着摆动。另外,这款HTML5狐狸奔跑动画也是基于SVG的,前面我们也介绍过很多哦 SVG的动画效果,可见SVG在动画制作上也有很大的优势。

html5-svg-fox-run-animation

在线演示         源码下载

7、很有个性的CSS3弹跳Loading动画

今天我们要来分享一款非常具有创意的CSS3 Loading动画,这款CSS3 Loading动画是一个跳动的小球和几个滚动的小球组合而成,效果非常不错,我们也可以回顾一下之前分享的Loading动画,像这款 HTML5/CSS3超欢乐的小球跳动Loading动画特效也非常有特点。

css3-loading-jump

在线演示         源码下载

8、HTML5/CSS3奔跑动画 动画效果非常逼真

今天要分享一款很酷的模拟真人奔跑动画,它主要是利用 HTML5/CSS3技术结合多张图片的切换来实现的。这款 HTML5动画的逼真之处在于人物在奔跑的时候很有节奏感,而且有人物的投影。更重要的是当人物跑的越来越近是,人物的大小也会随之变大。很像一个小男孩从远处跑过来。

html5-boy-run-animation

在线演示         源码下载

9、一套HTML5/SVG表情图标 表情超可爱

这次我们要来向大家分享一款超级可爱的HTML5/SVG表情图标,一共有12组不同的表情,这些表情都是利用SVG Path绘制而成,对SVG熟悉的朋友应该觉得比较简单,但是这些表情的创意确实非常不错,你可以将这些svg表情应用到你的博客上去,非常可爱。

html5-svg-face-icon

在线演示         源码下载

以上就是9款优质的HTML5动画特效,大开眼界了吧,欢迎收藏分享。


浏览器特性检测工具:Modernizr

$
0
0

10年前,只有最尖端的网站设计师会为网页的布局和修饰使用CSS。那时的浏览器对CSS进行布局的支持既不完善又漏洞百出,所以他们在坚持WEB标准化的同时,不得不采用hacks来使得他们的页面在所有浏览器中都能正常显示。其中一个被使用的最多的hack技术是浏览器嗅探(browser sniffing),使用Javascript里的navigator.userAgent属性来判断用户使用的是什么品牌哪个版本的浏览器。浏览器嗅探技术可以快捷的将代码进行分支,以便针对不同的浏览器应用不同的指令。

今天,以CSS为基础进行的布局已经非常普遍,浏览器们对它的支持也非常的坚实。但是现在CSS3和HTML5来了,历史转了个圈又回到了原地——各个浏览器对这些新技术的支持又开始变得参差不齐了。面对这样的问题,我们该怎么做呢?简单!使用特征检测(feature detection),这意味着我们不必通过问浏览器“你是谁?”来做出不靠谱的推测。取而代之我们问浏览器“你能做这个或那个吗?”。

想要一个个检测浏览器对特性的支持,看上去是个繁琐的工作,好在有了 Modernizr的帮助。Modernizr 是一个用来检测浏览器功能支持情况的 JavaScript 库。 目前,Modernizr 可以检测18项 CSS3 功能以及40多项关于HTML5 的功能。 它比传统检测浏览器名称(浏览器嗅探)的方式更为可靠。 一整套测试的执行时间仅需几微秒。

Modernizr是基于 渐进增强理论来开发的,所以它支持并鼓励开发者一层一层的创建他们的网站。一切从一个应用了Javascript的空闲地基开始,一个接一个的添加增强的应用层。因为使用了Modernizr,所以你容易知道浏览器都支持什么。

Modernizr 可轻松实现 JavaScript 解决方案,即人们熟知的 polyfills——它模拟HTML5 相关功能和技术,如地理定位。 然而,你的确需要对 JavaScript 有基本了解以便使用这些功能和技术。 术语polyfill 来源于一种填补裂缝的黏土的英国品牌Polyfilla(即美国人熟知的填泥料)。 这里,polyfill 用来填补浏览器功能上的漏洞。 有时,Modernizr 可无缝地执行这项任务。 但本质上,这只是一种修补工作,所以,不能依赖它产生无漏洞浏览器所实现的完全相同结果。

Modernizr提供development和production两个版本,development版本包含了对所有HTML5和CSS3新特性的检测,适用于学习和测试,对于刚开始使用Modernizr的新手来说,bella建议你使用这个版本。当你熟悉了Modernizr的工作原理后,你就可以使用production这个自定义版本,你可以只下载任意数量的你需要检测的特性从而大大减小下载量,这在某种程度上是能小幅提高你程序的性能的。你可以在http://modernizr.com/download/上下载这两个版本,点击该页面上的development version链接,就可以下载development版,或者,你已经看到了如下的特性显示页面。

相关资料:

1. Modernizr官网:  http://modernizr.com/docs/

2. Modernizr Test Suite网址: http://modernizr.github.com/Modernizr/test/index.html

3. shim/polyfill脚本的相关信息:  https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills

4. 各种检测HTML5和CSS3新特性的addTest函数下载地址: https://github.com/Modernizr/Modernizr/tree/master/feature-detects

Windows XP企业市场份额首次跌破10%

$
0
0

这家企业本周在博客中谈到,当前Windows XP在企业市场的使用率跌幅已远超平均水平。Net Applications的数据显示,目前在整个PC世界中,XP仍然占据着超过26%的市场;而Qualys的最新数据则显示,企业用户的Windows XP使用率在2013年1月份时还是大约32%,而在2014年5月的现如今,这个数字已经跌至将近8%。

这个消息对于企业或者微软来说都应该是好消息,这从大方向上表示企业用户正在响应微软的号召,将旧版Windows系统升级到更新的版本。因为只有升级到最新版本,这些PC才能享受到后续的支持和保护,微软仍将继续支持的系统包括了Vista、7、8、8.1。微软本周早前还发布了友情提醒,告知所有用户,Windows XP系统今后将不会再收到任何来自官方的安全升级。

Java SE 6 故障排除指南 – 5、挂起或循环进程故障排除

$
0
0

本章为挂起或循环进程的故障排除在特定程序上提供了信息和指导。

问题在涉及挂起或循环进程时发生。挂起可能因为多种原因发生,但经常是源于程序代码、API代码或库代码里的死锁。挂起甚至是因为 HotSpot VM的bug。

有时候,一个表面上是挂起的可能是个循环。例如,VM进程里的bug导致一个或多个线程进入死循环,会消耗掉所有可得CPU周期。

诊断挂起的最初步骤是找出VM进程是空闲还是消耗了所有可得CPU周期,为做这个要求使用操作系统工具。如果进程表现为繁忙且消耗了所有可得CPU周期,那么问题很可能是循环线程而不是死锁。

5.1 诊断循环进程

如果VM进程表现为循环,第一步是尝试获取线程转储。如果获取了线程转储,通常哪个线程在循环是很明显的。如果循环线程被认定,线程转储里的栈轨迹可以提供线程在哪里(可能还有为什么)循环的方向。

如果程序控制台(标准输入输出)可得,按下 Ctrl-\键组合(Solaris OS 或 Linux上)或 Ctrl-Break键组合(Windows上)引起 HotSpot VM 打印线程转储,包括线程状态。在Solaris OS 和Linux上,线程转储还可以通过发送 SIGQUIT到进程(命令: kill -QUIT <pid>)来获得。在这种情况下,线程转储将被打印到目标进程的标准输出。输出也可以重定向到文件,取决于进程如果启动。

如果Java进程是带 -XX:+PrintClassHistogram选项启动的, Ctrl-Break处理将生成堆直方图histogram。

如果线程转储被获取了,runnable状态的线程的线程轨迹是个好的起点。线程转储的格式的更多信息见 2.15.1 节,还有线程转储里可能的线程状态表格。在有些情况下,可能需要获取一序列线程转储来确定哪个线程是持续繁忙的。

如果程序控制台不可得(进程运行在后台或VM输出被重定向到未知地方),jstack 工具可用于获取线程轨迹。用 jstack -F pid选项来强制循环进程生成栈转储。从2.11节查看这个工具的输出的信息。jstack 工具也用于如果线程转储不能提供Java 线程循环的证据的情况。

当查看 jstack 工具的输出时,开始时专注于处于 RUNNABLE状态的线程。这个状态很可能是因为线程是繁忙和循环。可能需要执行 jstack 多次来获得一个线程循环的完整图(译注:也就是通过对比一序列转储来确定)。如果一个线程总是表现为 RUNNABLE状态, -m选项可用于打印本地帧和提供线程在做什么的更多提示。如果线程在 RUNNABLE状态表现出持续循环,这个情况指示了一个潜在的 HotSpot VM bug,需要进一步调查。

如果VM不响应 Ctrl-\,这可能指示了VM bug而不是程序或库代码的问题issue。在这种情况下, jstack -m -F可用于获取所有线程的栈。这个输出将包括VM内部线程的栈。在这个栈轨迹里,标识那些没有表现出等待的线程。

5.2 诊断挂起进程

如果程序表现出挂起且进程表现出空闲,那么第一步是尝试获取线程转储。如果程序控制台可得,按下 Ctrl-\(Solaris OS 或 Linux上)或 Ctrl-Break(Windows上)引起 HotSpot VM 打印线程转储 。在Solaris OS 和Linx上,线程转储还可以通过发送 SIGQUIT到进程(命令: kill -QUIT <pid>)来获得。

5.2.1 检测到死锁

如果挂起进程能够生成线程转储,输出将被打印到目标进程的标准输出。打印线程转储之后,HotSpot VM 执行一个死锁检测算法。如果检测到死锁,死锁将与涉及死锁的线程的栈轨迹一起输出。下面是输出示例:

Found one Java-level deadlock:
============================="AWT-EventQueue-0":
  waiting to lock monitor 0x000ffbf8 (object 0xf0c30560, a java.awt.Component$AWTTreeLock),
  which is held by "main""main":
  waiting to lock monitor 0x000ffe38 (object 0xf0c41ec8, a java.util.Vector),
  which is held by "AWT-EventQueue-0"

Java stack information for the threads listed above:
===================================================
"AWT-EventQueue-0":
        at java.awt.Container.removeNotify(Container.java:2503)
        - waiting to lock <0xf0c30560> (a java.awt.Component$AWTTreeLock)
        at java.awt.Window$1DisposeAction.run(Window.java:604)
        at java.awt.Window.doDispose(Window.java:617)
        at java.awt.Dialog.doDispose(Dialog.java:625)
        at java.awt.Window.dispose(Window.java:574)
        at java.awt.Window.disposeImpl(Window.java:584)
        at java.awt.Window$1DisposeAction.run(Window.java:598)
        - locked <0xf0c41ec8> (a java.util.Vector)
        at java.awt.Window.doDispose(Window.java:617)
        at java.awt.Window.dispose(Window.java:574)
        at javax.swing.SwingUtilities$SharedOwnerFrame.dispose(SwingUtilities.java:1743)
        at javax.swing.SwingUtilities$SharedOwnerFrame.windowClosed(SwingUtilities.java:1722)
        at java.awt.Window.processWindowEvent(Window.java:1173)
        at javax.swing.JDialog.processWindowEvent(JDialog.java:407)
        at java.awt.Window.processEvent(Window.java:1128)
        at java.awt.Component.dispatchEventImpl(Component.java:3922)
        at java.awt.Container.dispatchEventImpl(Container.java:2009)
        at java.awt.Window.dispatchEventImpl(Window.java:1746)
        at java.awt.Component.dispatchEvent(Component.java:3770)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
        at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:214)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:163)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:157)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:149)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)"main":
        at java.awt.Window.getOwnedWindows(Window.java:844)
        - waiting to lock <0xf0c41ec8> (a java.util.Vector)
        at javax.swing.SwingUtilities$SharedOwnerFrame.installListeners(SwingUtilities.java:1697)
        at javax.swing.SwingUtilities$SharedOwnerFrame.addNotify(SwingUtilities.java:1690)
        at java.awt.Dialog.addNotify(Dialog.java:370)
        - locked <0xf0c30560> (a java.awt.Component$AWTTreeLock)
        at java.awt.Dialog.conditionalShow(Dialog.java:441)
        - locked <0xf0c30560> (a java.awt.Component$AWTTreeLock)
        at java.awt.Dialog.show(Dialog.java:499)
        at java.awt.Component.show(Component.java:1287)
        at java.awt.Component.setVisible(Component.java:1242)
        at test01.main(test01.java:10)

Found 1 deadlock.

默认的死锁检测可以和通过 synchronized关键字获取的锁,还有通过 java.util.concurrent包获取的锁一起工作。如果设置了 JVM 的 -XX:+PrintConcurrentLocks标记,那么栈轨迹也显示锁属主的列表。

如果检测到死锁,你必须更详细地检验来理解死锁。在上面的例子里,线程 main锁定了对象 <0xf0c30560>,并等待进入 0xf0c41ec8,它是由线程 AWT-EventQueue-0锁定的。然而,线程 AWT-EventQueue-0正在等待 0xf0c30560,而它是由线程 main锁定。

栈轨迹里的详细信息提供了查找死锁的帮助。

5.2.2 未检测到死锁

如果线程转储被打印且没有发现死锁,那么问题可能是个bug,线程在监视器上等待但从未收到通知。这可能是个定时timing问题或一般的逻辑错误。

为找出问题的更多信息,检查线程转储里的每个线程和每个阻塞在 Object.wait()的线程。栈轨迹里的调用帧指示了正在调用 wait()的类和方法。如果代码编译时(默认)包含了行号信息,这直接提供了检查的方向(译注:可以直接看到哪行源码在调用 wait 方法)。大多数情况下,为进一步诊断问题,你必须有程序逻辑或库的知识。通常,你必须明白程序的同步是如何工作的,特别是监视器何时、何地被通知的细节和条件。

5.2.3 没有线程转储

如果VM不响应 Ctrl-\Ctrl-Break,可能是VM死锁了或由于其它原因挂起了。在那样的情况下用 jstack 工具来获取线程转储。 jstack -F pid选项来强制挂起进程的线程转储。这也可以用于于程序不能访问或输出被重定向到未知地方。

在 jstack 的输出里,检查每个处于 BLOCKED状态的线程。顶层帧有时能指示线程为什么被阻塞了,例如 Object.waitThread.sleep。栈的其余部分将给出线程正在做什么。特别是源码被编译了行号信息,你可以交叉引用源代码。

如果线程处于 BLOCKED状态且理由不明显,用 -m选项来获取一个混合栈。在混合栈的输出里,你应该可以确定线程为什么被阻塞了。如果线程因为尝试进入同步方法或块而阻塞,你将在顶层帧附近看到类似 ObjectMonitor::enter的帧。举例:

----------------- t@13 -----------------
0xff31e8b8      ___lwp_cond_wait + 0x4
0xfea8c810      void ObjectMonitor::EnterI(Thread*) + 0x2b8
0xfeac86b8      void ObjectMonitor::enter2(Thread*) + 0x250
:

处于 RUNNABLE状态的线程也可能阻塞。混合栈里的顶层帧应当指示线程正在做什么。

一个需要检查的特定线程是 VMThread。这个特定线程用于执行像垃圾回收的动作。它可以通过线程的初始栈是否正在执行 VMThread::run()来鉴别。在Solaris OS上典型的是 t@4,在Linux上是用 C++ mangled名字 _ZN8VMThread4loopEv

通常,你可以从命令行执行程序,你可以得到VM不响应 Ctrl-\Ctrl-Break的状态,很可能是你揭露了一个VM bug,一个线程库问题issue,或其他库的bug。如果这个发生,获取一个崩溃转储,尽可能多地收集信息,提交bug报告或支持电话。

在挂起进程上下文要提及的另一个工具是Solaris OS 的 pstack 工具。Linux上与 pstack等价的工具是 lsstack。在写这篇文档时 lsstack只能报告本地栈帧。

TODO。

5.3 Solaris 8 OS 线程库

TODO

Java SE 6 故障排除指南 – 3、内存泄露

$
0
0

内存泄露故障排除

如果你的应用程序执行的时间越来越长,或如果操作系统执行越来越慢,这可能是内存泄露的指示。换句话说,虚拟内存被分配但在不需要时没有归还。最终应用程序或系统没有可用内存,应用程序非正常终止。

这篇文章提供了一些涉及内存泄露的问题诊断的建议。

3.1 OutOfMemoryError 的含义

一个最常见的内存泄露的指示是 java.lang.OutOfMemoryError 错误。这个错误在Java堆或堆的特定区域没有足够空间用于分配对象时抛出。垃圾收集器不能创造更多可用空间来容纳一个新的对象,堆也不能扩展。

当 java.lang.OutOfMemoryError 错误抛出时,栈轨迹也会被打印。

java.lang.OutOfMemoryError 也可以被本地库代码抛出,当本地分配不能满足时,例如,交换空间很低。

诊断 java.lang.OutOfMemoryError 的一个早期步骤是确定错误的含义。它是否意味着Java堆满了,或意味着本地堆满了?为帮助你回答这个问题,下面的子章节解释了一些可能的错误信息,还有连接到更详细信息的链接:

  • “main” 线程里的 java.lang.OutOfMemoryError 异常:Java 堆空间。详见 3.1.1。
  • “main” 线程里的 java.lang.OutOfMemoryError 异常:Java PermGen空间。详见 3.1.2。
  • “main” 线程里的 java.lang.OutOfMemoryError 异常:请求的数组大小超过VM限制。详见 3.1.3。
  • “main” 线程里的 java.lang.OutOfMemoryError 异常: request <size> bytes for <reason>. Out of swap space?
  • request bytes for . Out of swap space? 详见 3.1.4
  • “main” 线程里的 java.lang.OutOfMemoryError 异常: java.lang.OutOfMemoryError: <reason> <stack trace> (Native method),详见 3.1.5

3.1.1 Java堆空间详细信息

Java堆空间详细信息指出了对象不能再Java里分配。这个错误不是必然表示内存泄露。这个问题可能仅仅只是配置问题,指定的堆大小不能满足应用程序。

在其他情况下,特别是长期存活的应用程序,这个消息可能指示了应用程序无意地持有对象的引用,这导致对象不能被垃圾收集。这是Java语言等价的内存泄露。注意,应用程序调用的API也可能无意地持有对象的引用。

另一个潜在的可能抛出 OutOfMemoryError 的来源是应用程序过多使用finalizer。如果类有 finalize 方法,那么那种类型的对象在垃圾收集时不回收它们的空间。而是,在垃圾收集后,对象排队等待 finalization,这在稍后的时间发生。在 Sun 的实现里,finalizer由一个守护线程执行,服务于 finalization 队列。如果 finalizer 线程不能跟上 finalization 队列,那么Java堆将充满, OutOfMemoryError 将被抛出。导致折衷情况的一个情景是应用程序创建高优先级线程,导致finalization 队列增加的速率快于 finalizer 线程服务那个队列的速率。3.3.6节讨论了如何管理等待finalization的对象。

3.1.2 PermGen 空间详细信息

PermGen 空间详细信息指示了永久代是满的。永久代是堆的一块区域,存储了类和方法对象(元数据)。如果应用程序加载了大量的类,那么永久代的大小可能需要增加,用 -XX:MaxPermSize选项。

interned的 java.lang.String 对象也存储在永久代。java.lang.String 类维持了一个字符串池。当 intern方法调用时,这个方法检查池来看等价的字符串是否已存在于池里。更准确的角度, java.lang.String.intern方法用于获取字符串的标准表示,结果是同一类的实例的引用将被返回,如果字符串作为标量出现。如果应用程序intern了大量的字符串,永久代可能需要增长。

当这类错误发生时,文本 String.internClassLoader.defineClass可能出现在栈轨迹的附近。

jmap -permgen命令打印永久代里对象的统计信息,包括 internalized 的字符串实例信息。见 2.7.4 获取永久代信息。

3.1.3 请求的数组大小超过VM限制 详细信息

“请求的数组大小超过VM限制” 详细信息指示了应用程序尝试分配一个数组,它的大小大于堆的大小。例如,应用程序尝试分配 512MB 的数组,但堆大小的最大值是 256MB,那么 OutOfMemoryError 将以 “请求的数组大小超过VM限制” 的理由抛出。大多数情况下,这个问题要么是配置问题,要么是应用程序的bug,尝试创建一个超级大的数组。

3.1.4 request <size> bytes for <reason>. Out of swap space?详细信息

这个信息以 OutOfMemoryError 形式出现。然而,HotSpot VM代码报告这个表面异常,当从本地堆分配失败和本地堆可能接近耗尽。这个消息指示了失败的请求的大小(按字节),和内存请求的理由。大多数情况下消息的 <reason>部分是报告分配失败的源模块的名字,虽然有些情况下它指示了理由。

当这个错误消息被抛出时,VM发起致命错误处理机制,它生成一个致命错误日志文件,包含了关于线程、进程和崩溃时系统的有用信息。在本地堆耗尽的情况下,日志里的堆内存和内存映射信息将有用。

如果这类 OutOfMemoryError 被抛出,你可能需要使用操作系统上的故障排除实用程序来诊断议题issue。

这个问题可能跟应用程序无关,例如:

  • 操作系统配置了不充足的交换空间。
  • 系统上的另一个进程消耗了所有内存资源。

3.1.5 java.lang.OutOfMemoryError: <reason> <stack trace> (Native method)详细信息

如果在错误信息的详细部分是 <reason> <stack trace> (Native method),且栈轨迹将被打印,最顶部的帧是本地方法,那么这指示了本地方法遭遇了分配失败。这个与前一个消息的区别是分配失败是在JNI或本地方法而不是在Java VM 代码里检测到。

3.2 崩溃而不是 OutOfMemoryError

有时候应用程序在本地堆分配失败后马上就崩溃了。这在本地代码不检查内存分配函数返回的错误时出现。

例如,如果没有可用内存时 malloc系统调用返回 NULL。如果 malloc的返回没有被检查,当尝试访问一个非法内存地址时应用程序可能崩溃。依赖于环境,这种类型的issue可能很难定位。

然而,来自致命错误日志或崩溃转储的信息足以诊断这个issue。致命错误日志在 附录C 里。如果崩溃的原因被确定为没有检查分配失败,那么分配失败的理由必须被验证。与其他本地堆issue一样,系统可能没有配置足够的交换空间,系统里的其它进程消耗了所有内存资源,或应用程序里有泄露,导致系统没有内存。

3.3 Java 语言代码里的泄露诊断。

诊断Java语言代码里的泄露是个困难的任务。大多数情况下,它要求对应用程序非常详细的知识。另外过程通常是反复和冗长的。这节提供了下面的子章节:

  • 3.3.1 NetBeans Profiler
  • 3.3.2 使用 jhat 实用程序
  • 3.3.3 创建堆转储
  • 3.3.4 获取正在运行进程的堆 histogram
  • 3.3.5 在 OutOfMemoryError 时获取堆的histogram
  • 3.3.6 监视等待 finalization 对象的数量
  • 3.3.7 第三方内存调试器

3.3.1 NetBeans Profiler

NetBeans Profiler 是个非常出色的剖析器,可以快速定位内存泄露。多数商业内存泄露调试工具需要很长时间来定位大应用程序里的泄露。NetBeans Profiler 使用内存分配模式和回收这些对象的典型通常证明。这个处理液包括缺乏内存回收。剖析器能够检查这些对象在哪里分配,在大多情况下这足以识别导致泄露的根源。

更多信息见 http://profiler.netbeans.org

3.3.2 使用 jhat 实用程序

jhat 工具队调试无意保留的对象(或内存泄露)有用。它提供了一种方法来浏览对象转储,查看堆里的所有可达对象,知道那个引用保留了存活对象。

为使用 jhat 你必须获取一个或多个正在运行程序的堆转储,这些转储必须是二进制格式的。一旦转储文件创建,它可以作为 jhat 的输入,见 2.5 节。

3.3.3 创建堆转储

堆转储提供了堆内存分配的详细信息。

3.3.3.1 HPROF 剖析器

HPROF 剖析器代理可以创建在执行程序的堆转储。下面是命令行示例:
java -agentlib:hprof=file=snapshot.hprof,format=b application

如果VM是嵌入式的或不是用命令行启动器启动的,那么可以用 JAVA_TOOLS_OPTIONS环境变量来自动把 -agentlib选项加入命令行,见 A.2 。

一旦程序与HPROF一起运行,堆转储可以在程序命令行用 Ctrl-\Ctrl-Break创建。在 Solaris OS 和 Linux上一个可选的方法是发送 QUIT信号,用 kill -QUIT pid命令。当信号被接受后,堆转储将被创建;在上面的例子里,文件 snapshot.hprof将被创建。

堆转储文件保护所有原始数据和栈轨迹。

一个转储文件可以包含多个堆转储。如果 Ctrl-\Ctrl-Break被按了多次,后续的转储将被追加到文件。jhat 工具用 # n语法来区别转储, n是转储号。

3.3.3.2 jmap 工具

也可以用 jmap 工具来获取堆转储: jmap -dump:format=b,file=snapshot.jmap process-pid

不管JVM如何启动,jmap 工具可以生成堆转储快照,在上面的例子里,文件被叫作 snapshot.jmap。jmap 输出文件应该包含所有原始数据,但不包括任何显示对象在哪里创建的栈轨迹。

3.3.3.3 JConsole 工具

获取堆转储的另一个方法是用JConsole工具,选择 HotSpotDiagnostic MBean,显示 Operations,选择 dumpHeap 选项。

3.3.3.4 -XX:+HeapDumpOnOutOfMemoryError命令行选项

如果指定了 -XX:+HeapDumpOnOutOfMemoryError命令行选项,且如果抛出了 OutOfMemoryError,VM将生成堆转储。

3.3.4 在运行进程上获取堆 histogram

你可以通过检查堆histogram来尝试快速缩小内存泄露范围。可以用下面的方法获取这个信息:

  • 用命令 jmap -histo pid来获取。输出显示了总的大小和堆里每种类型的实例数量。如果一序列histogram被获取(例如每隔2分钟),你将可以观察到一个趋势,引向进一步分析。
  • 在Solaris OS和Linux上,jmap工具也可以从core文件提供histogram。
  • 如果Java进程是带 -XX:+PrintClassHistogram选项启动,Ctrl-Break 处理器将生成堆histogram。

3.3.5 OutOfMemoryError 时获取堆histogram

如果指定了 -XX:+HeapDumpOnOutOfMemoryError选项,且如果抛出了 OutOfMemoryError,VM将生成堆转储。你可以用 jmap 工具从堆转储获取histogram。

如果抛出 OutOfMemoryError 时生成了core文件,你可以在core文件上执行 jmap 来获得 histogram,如下:

$jmap -histo \ /java/re/javase/6/latest/binaries/solaris-sparc/bin/java core.27421

Attaching to core core.27421 from executable 
/java/re/javase/6/latest/binaries/solaris-sparc/bin/java, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 1.6.0-beta-b63
Iterating over heap. This may take a while...
Heap traversal took 8.902 seconds.

Object Histogram:

Size      Count   Class description
-------------------------------------------------------
86683872  3611828 java.lang.String
20979136  204     java.lang.Object[]
403728    4225    * ConstMethodKlass
306608    4225    * MethodKlass
220032    6094    * SymbolKlass
152960    294     * ConstantPoolKlass
108512    277     * ConstantPoolCacheKlass
104928    294     * InstanceKlassKlass
68024     362     byte[]
65600     559     char[]
31592     359     java.lang.Class
27176     462     java.lang.Object[]
25384     423     short[]
17192     307     int[]
:

示例表明OutOfMemoryError 是由 java.lang.String 对象的数量(堆里有3611828个实例)导致的。没有进一步分析是不知道字符串是在哪分配的。然而信息仍然是有用的,继续调查可以用 HPROF 或 jhat 来找出字符串是在哪分配的,和哪些引用让它们保持存活,阻止它们被垃圾回收。

3.3.6 监视等待 finalization 的对象数量

如3.1.1节提到,过度使用 finalizer可以导致 OutOfMemoryError 。你有多种选择来监视等待finalization 的对象数量:

  • JConsole 管理工具可用于监视等待finalization的对象数量。这个工具报告等待finalization的计数,在内存统计信息的 “Summary” 标签面板。这个计数是估算的,但它可用于描绘应用特征,明白它依赖于大量finalization。
  • 在Solaris OS和Linux上, jmap -finalization选项打印等待finalization的对象信息。
  • 应用可以用 java.lang.management.MemoryMXBean类的 getObjectPendingFinalizationCount方法来报告大约的等待finalization对象的数量。

3.3.7 第三方内存调试器

除了前面章节提到的工具,还有很多第三方的内存调试器可用。JProbe from Quest Software, and OptimizeIt from Borland are two examples of commercial tools with memory debugging capability. There are many others and no specific product is recommended。

3.4 诊断本地代码里的泄露

有些技术可用于找出和隔离本地代码内存泄露。一般没有单一理想的解决方案适用于所有平台。

3.4.1 跟踪所有内存分配和释放调用

一个最常见的实践是跟踪所有的本地分配和释放。这可能是个非常简单的过程也可以是非常复杂的。

3.4.2 跟踪JNI库里的内存分配

TODO

3.4.3 用OS支持跟踪内存分配

TODO

3.4.4 用 dbx 查找泄露

TODO

3.4.5 用 libumem 查找泄露

TODO

博客启用InstantClick

$
0
0

博客» IT技术» »

之前我发现有些网站能瞬间显示新页面,几乎没有延迟,非常类似于AJAX的刷新,但页面URL的确又变了(如果是AJAX刷新,页面地址不会变)。现在我知道这可以用InstantClick实现。本着阅微堂一直在尝鲜最新技术的传统,我毫不犹豫就装上了。

InstantClick的官方主页见 http://instantclick.io/download。根据官方描述,它主要从两个方面加快页面加载速度:

  1. 网页浏览者在将鼠标挪到链接上(MouseOver)到点击鼠标(MouseDown)到点击完毕(MouseUp)一般都有400毫秒以上。不信的人可以到 http://instantclick.io/click-test这里测试一下自己的点击速度。浏览器一般在链接点击完毕后开始载入新页面。InstantClick则一旦发现鼠标挪到链接上就开始载入链接的页面内容,这可以让新页面的载入节约400毫秒以上。这个方法在手机浏览也有效。
  2. InstantClick使用pushState和Ajax技术,在显示新页面时并不是重新解释执行新页面,而只是替换页面的标题和页面内容。这样做有两个好处:其一是浏览器省去了重新解释代码和式样,让页面显示速度更快,尤其对于那些页面复杂和式样较多的页面;其二是浏览器可以无缝显示,不会在页面跳转中间闪一下白屏。

具体效果可以直接参考本博客。当网速较慢时,页面上方会显示载入进度条。

由于上面的第二个技术,这个插件只对使用同样式样文件的页面才有效,否则会出现白屏等情况。而且插件并不会自动识别,需要人工把这类链接加入黑名单。插件在这方面还可改进。

另外,该插件由于在原页面上直接更新内容,导致部分JavaScript会出问题。比如百度分享的代码必须在代码最前方加入以下代码才能正常工作:

window._bd_share_main


© 张志强 for 阅微堂, 2014. | 链接 | 0条评论

17画画 – 超好用的在线绘画软件

$
0
0

17画画是一款易上手的在线绘画软件,并画笔压感上做了不少改进,使线条更真实地模拟出自然画笔的感觉。@Appinn

17画画   超好用的在线绘画软件[图] | 小众软件

17画画设定有多种笔刷:钢笔、水彩笔、毛笔等。同时可以精确地设定笔触的粗细,并且有鼠标防抖,也支持数位板。

17画画在功能上有日本 SAI的感觉,但又比 SAI 做得更细致贴心。

17画画   超好用的在线绘画软件[图] | 小众软件

17画画还可以记录绘画过程,在 17画画网站上看到其他人分享的作品。

17画画   超好用的在线绘画软件[图] | 小众软件官网地址


©2014 dolyn for 小众软件 | 加入我们 | 投稿 | 订阅指南 | 反馈(图片不正常等问题)
b27c41ad47c2611d60d7452a4c02dd52
17画画   超好用的在线绘画软件[图] | 小众软件

苹果发明可识别互通短信人身份的技术专利

$
0
0

美国专利商标局今天公布了一项苹果提交的专利申请,这项专利起名为“显示基于联系人的用户界面”,描述的是一种可以帮助用户了解正在和谁互通短信的新型技 术,允许用户通过像 iMessage 之类的应用更好的弄清通信人的身份以及相貌。根据专利文件的描述,这项专利主要针对的是群体聊天的情况。

正如专利名称所显示的一样,这一种辨别身份的技术主要是基于 iPhone 用户设备里的联系人名单。据了解,新技术会通过用户联系人名单里的绑定头像进行辨别,如果联系人没有绑定头像,系统会分别针对男性和女性自动显示相关的默认头像。另外,用户在聊天时还可以在自己的设备上看到对方是否已经收到、又或者是正在准备发送信息的画面。

苹果还表示,这一项功能对于电子邮件同样有效。对于那些经常需要进行群聊天的商务人士,这一项发明可谓作用巨大。由于用户在商务领域经常会遇到各种各样的(准)合作伙伴,因此他们在进行群聊天的时候如果能够迅速辨别对方身份,有助于双方进行更深入的商务讨论。

 


© 推荐 for 互联网的那点事. | 猛击下载: iPhone客户端猛击下载: Android客户端


报表之间的勾稽关系都有什么?

$
0
0
叔的如何判断会计报表信息质量提过这事,没有专门说过。
要搞清报表勾稽关系先要了解四个主表,资产负债表,利润表,现金流量表,和所有者权益变动表
1、先说资产负债表、利润表和所有者权益变动表,这个关系主要体现在资产负债表的所有者权益部分和利润表之间,因为资产负债表是时点数,利润表是期间数,口径不同,所以勾稽关系也主要在所有者权益部分,毕竟利润表赚得的就是所有者的收益。当然事事无绝对,不能说资产负债表的未分配利润期末减期初一定等于当期净利润,因为可能还有分红这个减项,所以要看勾稽关系,最关键的还是所有者权变动表,这个表是时点数结合期间发生额,最清楚,但因为与经营关系不密切,编的人不多,看得人更少;
2、还有就是资产负债表,利润表,现金流量表,这三个表的核心在现金流量表,可以说现金流量表的编制基础是资产表和利润表,一般来说,不看具体账,光靠前两个表,也可以把现金流量表的主要数字编出来,业务复杂的误差率要高一点,业务简单的,误差率就小,叔做过几家中型公司的现金流量表,只看两张表,编的数字一分不差。不过以上误差率指经营性现金流量净额,这个数字是现金流量表的核心,只要这个数字不出大差错,现金流量表就不能说编的不对。

— 完 —
本文作者: 猫大叔

【知乎日报】 你都看到这啦,快来点我嘛 Σ(▼□▼メ)

此问题还有 3 个回答,查看全部。
延伸阅读:
腾讯和易迅有什么关系?
腾讯如何处理「朋友网」和「QQ 空间」这两个产品的关系?

谷歌创始人公开信:谷歌的未来往哪走?

$
0
0

依照每年一度的惯例,谷歌创始人在公司网站上发布了今年的公开信。信中谈到了谷歌现在广泛开展业务的原因,以及投资新奇项目背后的理念。以下为谷歌“2013年创始人公开信”全文:

谢尔盖与我建立谷歌,是因为我们想要“开发服务,让它们改善尽可能多的人的生活”(见2004年招股书中创始人的一封信)。一直以来,我们都在坚持这个使命,把那些用户真正喜爱的新技术作为公司未来的赌注——从谷歌搜索到谷歌邮箱、Chrome、YouTube以及安卓。我们在较短的时间里参与到了很多领域中,所以人们自然会问,今天的谷歌到底算什么,未来的目标是什么?这是个好问题。

http://static.cnbetacdn.com/newsimg/2014/0515/25_1jtbz1ham.jpg_w600.jpg

搜索不止......

谷歌的核心是信息。知识会让人类进步,这个信念激励着我们。在还是孩子的时候,我俩就有很大的好奇心。我记得自己曾用大量时间阅读书籍和杂志,或是在家拆东西,想搞清楚它们运作的机理。今天,搞清楚事情的过程容易多了。你只需要打开谷歌搜索就能发现答案。搜索之所以有这样重要的意义,是因为即便是小小的知识就能让事情发生巨大的改变——无论是日常生活中看似琐碎的小事,例如避开塞车,还是说更重要的事情,例如非洲农民在思考如何能挽救自己的马铃薯庄稼。

谷歌搜索上的活动量级是惊人的。每月有超过1000亿次搜索(而其中15%的搜索内容是全新的),而且现在我们将索引升级到了以数秒为间隔,确保总是可以给人最新的结果。为了让生活更轻松,我们逐渐可以直接给出问题的答案。例如,像“哪个湖泊全球最深?(答案是西伯利亚的贝加尔湖,深1741米)”,“我的航班几点起飞?”,或者“一块薄饼有多少卡路里?”这样的问题都可以得到答案。而且我对我们在语音搜索上取得的进展非常激动,这项服务现在可以支持超过38种语言,包括新近加入的越南语和泰语。发问的最快、最简单方式通常都是说话,尤其是在使用移动设备时。

不过,从很多方面看,我们离打造自己梦想中的搜索引擎这个目标还有万里之遥。这种搜索引擎应该是在用户需要的时候,无需他们花什么力气,就能提供正确信息的工具。之所以说离这个目标很远,部分是因为从深层次上理解信息是个难题。Google Now正在应对这个挑战。它甚至可以在用户不发问的情况下提供信息,可以让人免去翻遍收件箱查找物流需要的订单号码这种苦恼,而把号码直接显示在屏幕上。基于兴趣的Google+推荐,也可以提供大量信息。我总是可以看到高度相关的东西,我最近在Google+中谈到过风筝冲浪,接着就看到了这段关于风筝冲浪历史的YouTube视频。

虽然它尚处早期,我们还是在背景理解上获得了长足的进步。如果想要改进人机交互,这就是至关重要的一点。想一想你上班的路程,你需要非常方便地看到交通信息,这样就可以做好准备,避免堵车。如果你要去赴另一个约会,你就需要知道从现在所在的位置要怎么走(而不是非要在屏幕上输入地点信息)。更丰富的背景也会让搜索更加自然,而不再是手动把一堆关键词敲到电脑里。我们离目标越来越近了:你可以直接问艾菲尔铁塔有多高,“它”是什么时候建立起来的。“它”在不同的背景里可以指代很多东西,理解了“它”代表的是什么,我们就可以让搜索变得可以交流。

生活在一个多屏世界中

由于设备的增多,确保人们能有效地在其间浏览就变得越来越重要。我们的Chrome浏览器可以流畅地运行在各种设备上,这款产品已经拥有了超过7.5亿用户,非常快,非常安全。在台式机上打开地图,当切换到移动设备时,同样的页面会被保留下来,让你继续查看。

想想照片吧:它们无疑可以成为多屏世界里的大麻烦。不同的设备上存储着不同的照片,找不到也无法分享,我们都体会过这种沮丧的滋味。G+可以即时将照片传导网上,方便你在任何设备上查看。更妙的是,如果手机丢了,也不会影响到你的照片。

在不到6年的时间里,有超过10亿部安卓设备被激活(而且这一速度还在加快)——为全球越来越多的应用开发者打造了一个绝佳的平台。看到这个产业链腾飞起来是非常令人激动的。在2013年,安卓开发者从用户处挣到的钱,平均起来是前一年的4倍还多。我们现在将安卓移植到手表这样的可穿戴产品上以及汽车上,让查找方位、打电话或听音乐变得非常容易。

Google Play网店背后的理念是相似的。用户可以在这里一站式下载应用、电影、书籍以及音乐,而且可以省去同步工作在任何设备上查阅这些内容。你在平板电脑上听的歌,切换到手机上同样存在。还有最近的谷歌电视棒Chromecast,用它我们就能更方便地在家里或朋友那里观看Google Play或是Netflix上的电影。你可以扔掉所有遥控器,靠手机或平板电脑控制电视,使用习惯完全和上网一样——就像在网上看YouTube一样。最妙的是,这款设备仅售35美元。

现在,如果没有优秀的设计,这一切都只是空想。我记得自己在密歇根大学上过一节关于实用性的课程。学生们必须挑选一个自己非常熟悉的项目(我选的是邮件),估算出让它开展不同的任务,需要专家开发多长时间。我从中获益颇多,明白了打造优秀的、有效的界面是件难事,比你想象得更贴近工程师的工作。这里放一个标签,那里放一个下拉菜单。你扔给人们越多的选项(即便从来不会被用到),人们完成工作的时间就越长。到现在人们还会谈论谷歌首页的简洁,说这是我们最初获得成功的一大因素。同样的原则没理由不能用在我们其他的产品上,特别是现在,有了如此多的设备和选择,有了如此多的机会让人分心。

上网是个尚未解决的问题

当然,这一切的前提都是假设你已经是20亿网民中的一员。其实在这之外还有50亿人。今天的世界有如此丰富的信息,但还有三分之二的人口却没有最基本的互联网连接,这不得不说是个悲剧。这就是为什么我对启动了“气球计划”(Project Loon)特别激动的原因。这个理念是在最偏僻的地区打造一个气球联成的网络(它们的高度是商用飞机的两倍),为乡村和偏远地区提供网络连接。很快,巴西东北部就会出现首个上网的教室,靠得就是“气球”。而且随着项目的深入开展,我们还希望能把这种联网的能力带给越来越多的人——创造出我们从未想过的机遇。

创新与再创新

有一只小而专注的团队,用不寻常的办法从基础做起,成就一番事业,这种感觉非常了不起。然而随着时间流逝,我意识到让团队斗志昂扬、充满干劲是件非常难的事情,因为大多数人接受的不是这种“登月”式的教育。他们倾向于假设事情是不可能的,或是会被失败吓倒。这就是我们为什么要投入如此多的精力,在谷歌招聘独立思考的人,并设定宏大的目标。因为只要你能找到合适的人,梦想够大胆,一般都能将目标实现。而且即便你失败,应该也能从中获益不少。

另外一种情况也真实存在。那就是很多公司会逐渐习惯自己做事的方式,只会做渐进式的改变。时间一长,这种渐进主义就会导致走上歧途,尤其是在科技行业,因为改变本身更像是种革命,而不是进化。这就是为什么我们要持续从长远出发,在下一代产品上押重注。在医疗保健领域,我们有Calico——这是一间由Genentech前任首席执行官Art Levinson带领的新公司,专注于健康和长寿;还有智能隐形眼镜Iris,可以改变糖尿病患者的生活。我们近期还收购了Nest,这家公司让暖气这些本是无爱的家居产品变得更有用。而且我们对新推出的谷歌购物速递服务(Google Shopping Express)——它可以提供当日送抵的服务,以及无人驾驶汽车(这已经无需解释!)都非常激动。在今天看来,这些都是非常疯狂的想法。但是,如果说过去有那么一点能证明我们今后的成功,那么用不了几年,现在的这些赌注看上去就不会那么不着边际了。

在谷歌成立16年后,我们才刚刚触及到梦想的表面。谢尔盖和我参与日常工作,对前景非常激动,对我们能与杰出的人才共事非常激动。谷歌人要让一切成为可能,让这些可能成为我们的未来。虽然世界千变万化,但激励我们的始终是我们自身的潜质,即改变人们今天生活,这一点从一开始就未曾更改。

拉里·佩奇

PostgreSQL与MySQL比较

$
0
0
from: http://bbs.chinaunix.net/thread-1688208-1-1.html

 

 

特性MySQLPostgreSQL
实例通过执行 MySQL 命令(mysqld)启动实例。一个实例可以管理一个或多个数据库。一台服务器可以运行多个 mysqld 实例。一个实例管理器可以监视 mysqld 的各个实例。
通过执行 Postmaster 进程(pg_ctl)启动实例。一个实例可以管理一个或多个数据库,这些数据库组成一个集群。集群是磁盘上的一个区域,这个区域在安装时初始化并由一个目 录组成,所有数据都存储在这个目录中。使用 initdb 创建第一个数据库。一台机器上可以启动多个实例。
数据库数据库是命名的对象集合,是与实例中的其他数据库分离的实体。一个 MySQL 实例中的所有数据库共享同一个系统编目。数据库是命名的对象集合,每个数据库是与其他数据库分离的实体。每个数据库有自己的系统编目,但是所有数据库共享 pg_databases。
数据缓冲区通过 innodb_buffer_pool_size配置参数设置数据缓冲区。这个参数是内存缓冲区的字节数,InnoDB 使用这个缓冲区来缓存表的数据和索引。在专用的数据库服务器上,这个参数最高可以设置为机器物理内存量的 80%。Shared_buffers缓存。在默认情况下分配 64 个缓冲区。默认的块大小是 8K。可以通过设置 postgresql.conf 文件中的 shared_buffers 参数来更新缓冲区缓存。
数据库连接客户机使用 CONNECT 或 USE 语句连接数据库,这时要指定数据库名,还可以指定用户 id 和密码。使用角色管理数据库中的用户和用户组。客户机使用 connect 语句连接数据库,这时要指定数据库名,还可以指定用户 id 和密码。使用角色管理数据库中的用户和用户组。
身份验证MySQL 在数据库级管理身份验证。 基本只支持密码认证。PostgreSQL 支持丰富的认证方法:信任认证、口令认证、Kerberos 认证、基于 Ident 的认证、LDAP 认证、PAM 认证
加密可以在表级指定密码来对数据进行加密。还可以使用 AES_ENCRYPT 和 AES_DECRYPT 函数对列数据进行加密和解密。可以通过 SSL 连接实现网络加密。可以使用 pgcrypto 库中的函数对列进行加密/解密。可以通过 SSL 连接实现网络加密。
审计可以对 querylog 执行 grep。可以在表上使用 PL/pgSQL 触发器来进行审计。
查询解释使用 EXPLAIN 命令查看查询的解释计划。使用 EXPLAIN 命令查看查询的解释计划。
备份、恢复和日志InnoDB 使用写前(write-ahead)日志记录。支持在线和离线完全备份以及崩溃和事务恢复。需要第三方软件才能支持热备份。在数据目录的一个子目录中维护写前日志。支持在线和离线完全备份以及崩溃、时间点和事务恢复。 可以支持热备份。
JDBC 驱动程序可以从 参考资料下载 JDBC 驱动程序。可以从 参考资料下载 JDBC 驱动程序。
表类型取决于存储引擎。例如,NDB 存储引擎支持分区表,内存引擎支持内存表。支持临时表、常规表以及范围和列表类型的分区表。不支持哈希分区表。 由于PostgreSQL的表分区是通过表继承和规则系统完成了,所以可以实现更复杂的分区方式。
索引类型取决于存储引擎。MyISAM:BTREE,InnoDB:BTREE。支持 B-树、哈希、R-树和 Gist 索引。
约束支持主键、外键、惟一和非空约束。对检查约束进行解析,但是不强制实施。支持主键、外键、惟一、非空和检查约束。
存储过程和用户定义函数支持 CREATE PROCEDURE 和 CREATE FUNCTION 语句。存储过程可以用 SQL 和 C++ 编写。用户定义函数可以用 SQL、C 和 C++ 编写。没有单独的存储过程,都是通过函数实现的。用户定义函数可以用 PL/pgSQL(专用的过程语言)、PL/Tcl、PL/Perl、PL/Python 、SQL 和 C 编写。
触发器支持行前触发器、行后触发器和语句触发器,触发器语句用过程语言复合语句编写。支持行前触发器、行后触发器和语句触发器,触发器过程用 C 编写。
系统配置文件my.confPostgresql.conf
数据库配置my.confPostgresql.conf
客户机连接文件my.confpg_hba.conf
XML 支持有限的 XML 支持。有限的 XML 支持。
数据访问和管理服务器OPTIMIZE TABLE—— 回收未使用的空间并消除数据文件的碎片
myisamchk -analyze—— 更新查询优化器所使用的统计数据(MyISAM 存储引擎)
mysql—— 命令行工具
MySQL Administrator—— 客户机 GUI 工具
Vacuum—— 回收未使用的空间
Analyze—— 更新查询优化器所使用的统计数据
psql—— 命令行工具
pgAdmin—— 客户机 GUI 工具
并发控制支 持表级和行级锁。InnoDB 存储引擎支持 READ_COMMITTED、READ_UNCOMMITTED、REPEATABLE_READ 和 SERIALIZABLE。使用 SET TRANSACTION ISOLATION LEVEL 语句在事务级设置隔离级别。支 持表级和行级锁。支持的 ANSI 隔离级别是 Read Committed(默认 —— 能看到查询启动时数据库的快照)和 Serialization(与 Repeatable Read 相似 —— 只能看到在事务启动之前提交的结果)。使用 SET TRANSACTION 语句在事务级设置隔离级别。使用 SET SESSION 在会话级进行设置。



MySQL相对于PostgreSQL的劣势:

MySQLPostgreSQL
最重要的引擎InnoDB很早就由Oracle公司控制。目前整个MySQL数据库都由Oracle控制。BSD协议,没有被大公司垄断。
对复杂查询的处理较弱,查询优化器不够成熟很强大的查询优化器,支持很复杂的查询处理。
只有一种表连接类型:嵌套循环连接(nested-loop),不支持排序-合并连接(sort-merge join)与散列连接(hash join)。都支持
性能优化工具与度量信息不足提供了一些性能视图,可以方便的看到发生在一个表和索引上的select、delete、update、insert统计信息,也可以看到cache命中率。网上有一个开源的pgstatspack工具。

InnoDB的表和索引都是按相同的方式存储。也就是说表都是索引组织表。这一般要求主键不能太长而且插入时的主键最好是按顺序递增,否则对性能有很大影响。

不存在这个问题。

大部分查询只能使用表上的单一索引;在某些情况下,会存在使用多个索引的查询,但是查询优化器通常会低估其成本,它们常常比表扫描还要慢。

不存在这个问题

表增加列,基本上是重建表和索引,会花很长时间。

表增加列,只是在数据字典中增加表定义,不会重建表

存储过程与触发器的功能有限。可用来编写存储过程、触发器、计划事件以及存储函数的语言功能较弱

除支持pl/pgsql写存储过程,还支持perl、python、Tcl类型的存储过程:pl/perl,pl/python,pl/tcl。

也支持用C语言写存储过程。

不支持Sequence。

支持

不支持函数索引,只能在创建基于具体列的索引。

不支持物化视图。

支持函数索引,同时还支持部分数据索引,通过规则系统可以实现物化视图的功能。

执行计划并不是全局共享的, 仅仅在连接内部是共享的。

执行计划共享

MySQL支持的SQL语法(ANSI SQL标准)的很小一部分。不支持递归查询、通用表表达式(Oracle的with 语句)或者窗口函数(分析函数)。

都 支持

不支持用户自定义类型或域(domain)

支持。

对于时间、日期、间隔等时间类型没有秒以下级别的存储类型

可以精确到秒以下。

身份验证功能是完全内置的,不支持操作系统认证、PAM认证,不支持LDAP以及其它类似的外部身份验证功能。

支持OS认证、Kerberos 认证 、Ident 的认证、LDAP 认证、PAM 认证

不支持database link。有一种叫做Federated的存储引擎可以作为一个中转将查询语句传递到远程服务器的一个表上,不过,它功能很粗糙并且漏洞很多

有dblink,同时还有一个dbi-link的东西,可以连接到oracle和mysql上。

Mysql Cluster可能与你的想象有较大差异。开源的cluster软件较少。

复制(Replication)功能是异步的,并且有很大的局限性.例如,它是单线程的(single-threaded),因此一个处理能力更强的Slave的恢复速度也很难跟上处理能力相对较慢的Master.

有丰富的开源cluster软件支持。

explain看执行计划的结果简单。

explain返回丰富的信息。

类似于ALTER TABLE或CREATE TABLE一类的操作都是非事务性的.它们会提交未提交的事务,并且不能回滚也不能做灾难恢复

DDL也是有事务的。






PostgreSQL主要优势:
  1. PostgreSQL完全免费,而且是BSD协议,如果你把PostgreSQL改一改,然后再拿去卖钱,也没有人管你,这一点很重要,这表明了 PostgreSQL数据库不会被其它公司控制。oracle数据库不用说了,是商业数据库,不开放。而MySQL数据库虽然是开源的,但现在随着SUN 被oracle公司收购,现在基本上被oracle公司控制,其实在SUN被收购之前,MySQL中最重要的InnoDB引擎也是被oracle公司控制 的,而在MySQL中很多重要的数据都是放在InnoDB引擎中的,反正我们公司都是这样的。所以如果MySQL的市场范围与oracle数据库的市场范 围冲突时,oracle公司必定会牺牲MySQL,这是毫无疑问的。
  2. 与PostgreSQl配合的开源软件很多,有很多分布式集群软件,如pgpool、pgcluster、slony、plploxy等等,很容易做读写分离、负载均衡、数据水平拆分等方案,而这在MySQL下则比较困难。
      3. PostgreSQL源代码写的很清晰,易读性比MySQL强太多了,怀疑MySQL的源代码被混淆过。所以很多公司都是基本PostgreSQL做二次开发的。
      4. PostgreSQL在很多方面都比MySQL强,如复杂SQL的执行、存储过程、触发器、索引。同时PostgreSQL是多进程的,而MySQL是线 程的,虽然并发不高时,MySQL处理速度快,但当并发高的时候,对于现在多核的单台机器上,MySQL的总体处理性能不如PostgreSQL,原因是 MySQL的线程无法充分利用CPU的能力。
     目前只想到这些,以后想到再添加,欢迎大家拍砖。


PostgreSQL与oracle或InnoDB的多版本实现的差别

PostgreSQL与oracle或InnoDB的多版本实现最大的区别在于最新版本和历史版本是否分离存储,PostgreSQL不分,而oracle和InnoDB分,而innodb也只是分离了数据,索引本身没有分开。
   PostgreSQL的主要优势在于:
   1. PostgreSQL没有回滚段,而oracle与innodb有回滚段,oracle与Innodb都有回滚段。对于oracle与Innodb来说, 回滚段是非常重要的,回滚段损坏,会导致数据丢失,甚至数据库无法启动的严重问题。另由于PostgreSQL没有回滚段,旧数据都是记录在原先的文件 中,所以当数据库异常crash后,恢复时,不会象oracle与Innodb数据库那样进行那么复杂的恢复,因为oracle与Innodb恢复时同步 需要redo和undo。所以PostgreSQL数据库在出现异常crash后,数据库起不来的几率要比oracle和mysql小一些。
   2. 由于旧的数据是直接记录在数据文件中,而不是回滚段中,所以不会象oracle那样经常报ora-01555错误。
   3. 回滚可以很快完成,因为回滚并不删除数据,而oracle与Innodb,回滚时很复杂,在事务回滚时必须清理该事务所进行的修改,插入的记录要删除,更新的记录要更新回来(见row_undo函数),同时回滚的过程也会再次产生大量的redo日志。
   4. WAL日志要比oracle和Innodb简单,对于oracle不仅需要记录数据文件的变化,还要记录回滚段的变化。
    PostgreSQL的多版本的主要劣势在于:
   1、最新版本和历史版本不分离存储,导致清理老旧版本需要作更多的扫描,代价比较大,但一般的数据库都有高峰期,如果我们合理安排VACUUM,这也不是很大的问题,而且在PostgreSQL9.0中VACUUM进一步被加强了。
  2、由于索引中完全没有版本信息,不能实现Coverage index scan,即查询只扫描索引,直接从索引中返回所需的属性,还需要访问表。而oracle与Innodb则可以;


进程模式与线程模式的对比
PostgreSQL和oracle是进程模式,MySQL是线程模式。
进程模式对多CPU利用率比较高。
进程模式共享数据需要用到共享内存,而线程模式数据本身就是在进程空间内都是共享的,不同线程访问只需要控制好线程之间的同步。
线程模式对资源消耗比较少。
所以MySQL能支持远比oracle多的更多的连接。
对于PostgreSQL的来说,如果不使用连接池软件,也存在这个问题,但PostgreSQL中有优秀的连接池软件软件,如pgbouncer和pgpool,所以通过连接池也可以支持很多的连接。

堆表与索引组织表的的对比

Oracle支持堆表,也支持索引组织表
PostgreSQL只支持堆表,不支持索引组织表
Innodb只支持索引组织表
索引组织表的优势:
表内的数据就是按索引的方式组织,数据是有序的,如果数据都是按主键来访问,那么访问数据比较快。而堆表,按主键访问数据时,是需要先按主键索引找到数据的物理位置。
索引组织表的劣势:
索引组织表中上再加其它的索引时,其它的索引记录的数据位置不再是物理位置,而是主键值,所以对于索引组织表来说,主键的值不能太大,否则占用的空间比较大。
对于索引组织表来说,如果每次在中间插入数据,可能会导致索引分裂,索引分裂会大大降低插入的性能。所以对于使用innodb来说,我们一般最好让主键是一个无意义的序列,这样插入每次都发生在最后,以避免这个问题。
由于索引组织表是按一个索引树,一般它访问数据块必须按数据块之间的关系进行访问,而不是按物理块的访问数据的,所以当做全表扫描时要比堆表慢很多,这可能在OLTP中不明显,但在数据仓库的应用中可能是一个问题。




  PostgreSQL9.0中的特色功能:   
    PostgreSQL中的Hot Standby功能
    也就是standby在应用日志同步时,还可以提供只读服务,这对做读写分离很有用。这个功能是oracle11g才有的功能。

    PostgreSQL异步提交(Asynchronous Commit)的功能:
  这个功能oracle中也是到oracle11g R2才有的功能。因为在很多应用场景中,当宕机时是允许丢失少量数据的,这个功能在这样的场景中就特别合适。在PostgreSQL9.0中把 synchronous_commit设置为false就打开了这个功能。需要注意的是,虽然设置为了异步提交,当主机宕机时,PostgreSQL只会 丢失少量数据,异步提交并不会导致数据损坏而数据库起不来的情况。MySQL中没有听说过有这个功能。

     PostgreSQL中索引的特色功能:
     PostgreSQL中可以有部分索引,也就是只能表中的部分数据做索引,create index 可以带where 条件。同时PostgreSQL中的索引可以反向扫描,所以在PostgreSQL中可以不必建专门的降序索引了。



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



大数据证明怎样让MOOC更吸引人

$
0
0

让学生更投入地学习是教师的责任之一。 MOOC的学生流失率一直是关注焦点,开课教师也会绞尽脑汁地吸引、鼓励学生,希望他们能坚持下去,哪怕只是多学一点点也好。最近读的两篇论文分别基于 coursera 和 edX 的数据,从不同角度分析了此问题,有些结论显而易见,有些结论令人惊讶,对开课教师以及平台设计和运营都很有借鉴意义。所以,摘要于此。

背景

先简单介绍一下这两篇论文的背景。论文《 Engaging with Massive Online Courses》(以下简称论文1)由斯坦福大学和康奈尔大学的博士生、教授合作,发表于计算机应用领域世界最顶级的学术会议之一—— WWW,并且获得了 最佳论文亚军,非常强大。论文通过挖掘 coursera 上  Machine Learning 和  Probabilistic Graphical Models 两门课各三次开课的数据记录,分析了最终成绩不同的学生在学习过程中表现出怎样的差异,以及如何提升课程论坛活跃度。

另一篇论文《 How Video Production Affects Student Engagement: An Empirical Study of MOOC Videos》由 MIT 的博士生、博士后,及 edX 工程副总裁共同撰写,发表于应 MOOC 兴起而新设立,专注于教育与计算机科学交叉学科的会议——ACM Learning @ Scale。它分析了edX上690万条视频观看记录,统计得出怎样的视频更吸引人。

结论综述

他们的具体分析方法就不赘述了,感兴趣的请看原文。这里直接进入结论综述。

课程开始前后选课的用户质量最高

在课程正式开始前半个月,到课程第一次作业截止这段时间里选课的学生,其中的活跃者比例远高于其它时间选课的。所以, MOOC课程宣传的最佳时机,就是开课前后这个时间窗口,能获取更优质的学员

早选课的活跃度低,可能是因为学习热情在等待中消散,或者时间发生了冲突。第一次作业截止时间之后,再努力学也难以获得证书,所以对后续作业等也就不关注了。不过值得一提的是,自开课时间起,哪怕到了课程结束之后,加入到课程但只看视频的学生始终保持着较高的比例。他们虽然不交作业、不考试,但也能从视频有所得,这也是课程价值的体现。所以 有些MOOC课程结束后就彻底关闭,连视频都不给人看的做法,是不合适的

另外,60%的学生是在课程开始前选课的,所以足够长的预告期还是有必要的。

学生越活跃,成绩越高

基本上, 学生的最终成绩和他在看视频、做测验、交作业和读论坛的次数是成正比的。也应了那句“一分耕耘一分收获”的老话。但“读论坛”这项活动有个独特现象,在80-100分这个区间会变成反比,也就是分数越高,论坛看得越少。这说明学霸对论坛的依赖不高。 论坛主要服务于 学霸

但不要以为学霸对论坛就没贡献,事实上他们很重要。统计数据表明, 占据论坛沙发的学生论坛活跃度都很高(侧面说明人数少),而且他们的平均成绩也在80分之上

最大的杀手,是做题

统计表明,并没有任何视频成为明显的学习终结者,但确实有些作业题目成为障碍,大量的学生被挂在上面,然后就没有然后了。这说明 学习中止的很大原因是遇到困难,而非单纯的懒惰。如果能在解题过程多提供一些帮助,可以帮学生走得更远。

学霸和学渣的帖子有显著区别

只需要对讨论区做简单的词频统计,就能得出一个结论: 交作业多的学生帖子包含更多术语,交作业少的则刷的只是存在感(hello、me、I’m、interested是学渣高频词)。如此说来,假如要对学生论坛表现评分的话,那么词频统计的方法也是有一定可行性的。

另一个区别是帖子的位置。前面说了,学霸喜沙发。那学渣喜什么呢?喜欢提问……其实说提问的是学渣,是不对的。虽然统计表明提问者的平均成绩较低,但还没低到学渣的地步。真正的学渣是连问都不会问的。

虚荣心是可利用的

ML的第三次授课在论坛里引入了游戏中常用的勋章系统,结果论坛活跃度提升了不少。而且,勋章的展现越显著(比如紧贴着用户姓名显示),越能刺激活跃度。当然,负面作用也有,就是恶意投票的增加了。

短于6分钟的视频最吸引人

基于edX数据的统计,无论视频多长,用户实际观看时长的中位数都不超过6分钟。而且6-9分钟长的视频是个拐点,更长的视频实际观看中位数反倒会下降。比如长度超过12分钟的视频,实际观看中位数只有3分钟。所以,“ 短视频到底多短最合适”这个问题有了标准答案了:6分钟。

这个数字挺难让人接受的,因为按多数老师的习惯,6分钟根本讲不了什么东西,15分钟都勉强。但和下一个结论联合分析,其实真未必做不到。

语速快,很关键

虽然统计数字表明语速和视频吸引力并不完全成正比,但当语速达到每分钟185-254个单词(对应中文我估计少说得300个字吧?)时,无论视频多长,都比低语速能获得更多注意力。原因很好理解,快语速常常伴随着激情,激情富有感染力,感染力可以让学生更专注。所以, 教师越热情,甚至是激情,越能吸引学生。

语速加快,讲同样内容所需时间就会缩短,这样产出的视频就可以向下接近甚至达到6分钟的建议长度了。 录课前做好规划,让内容更紧凑,节奏更快,不说废话,不机械重复(学生可以自己重复看),剪掉“嗯”、“啊”等口头语,短小精悍的视频就有了。

教师头像绝非可有可无

对于大于6分钟的视频,有教师讲课头像的和纯ppt、软件操作等录屏相比,前者收获的关注更多。我想,这是因为头像总在动,比时长处于静止画面的单调录屏更提神吧。我个人确实比较喜欢那种头像嵌入视频一角的形式,但前提是ppt把那一角特意留出来,头像不会遮挡该看到的课件内容。

制造一对一的感觉

教师都习惯教室气氛,黑板/大屏幕,站在讲台上,走来走去,甚至安排一些学生假装听众来提起讲课的性质。但数据分析表明,这种在教室/演播室,配置昂贵设备录制的视频,在吸引力上其实不如更低成本的私人录制方式。 教师坐着,面对镜头,背景就是办公室,像做单独辅导一样地讲课,效果是最好的。这样很容易产生一种亲切感,而且和坐在电脑前的学生所处学习环境最契合。

这里的关键点,就是让学生有一对一的感觉。坐下来直面镜头,就基本创造出了这种感觉。语言上再 多用“你”而不是“你们”,用“咱们”而不是“大家”,气氛就有了。很多不谙此道的老师课程开头第一句话总是“同学们,大家好”,我通常在那一刻就“出戏”了。

手写屏/笔是最值得购买的设备

可汗学院的视频是典型的手写笔应用,所以论文2干脆将这种视频称为“可汗风格”。统计表明,与录屏风格相比,学生愿意在可汗风格的视频中投入1.5-2倍的时间。老师边讲边画,确实很像一对一给我讲题的感觉。或者在一片白板/黑板上用板书讲课,或者在ppt上勾画要强调的内容,手写让学生很清楚地知道该看哪里,并忠实地跟着老师的思路。

用鼠标是很难“写”出好板书的。手写电磁屏用起来很直观,但也很昂贵。手写笔也够用,而且只卖几百元,非常值得配备一块。

RaspBerry Pi连接WiFi

$
0
0

推荐 EDUP EP-N8508GS无线网卡 树莓派专用,这个直接免驱,省去很多麻烦事

#cat /etc/network/interfaces
auto lo
iface lo inet loopback
iface eth0 inet dhcp
allow-hotplug wlan0
iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp

#sudo cat /etc/wpa_supplicant/wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
ssid="Home"
psk="1111111111"
proto=RSN
key_mgmt=WPA-PSK
pairwise=CCMP
auth_alg=OPEN
}
network={
ssid="Office"
psk="1111111111"
proto=RSN
key_mgmt=WPA-PSK
pairwise=CCMP
auth_alg=OPEN
}

无刷新修改页面的浏览器地址栏显示地址的方法

$
0
0

作为一个Web程序员,我经常会到网上去看别人是如何做网站,如何开发Web应用的。这样的好处有很多,一是开阔你的眼界,你能看到很多书本上没有的东西,二是看别人的代码是如何写的,取人之长、补己之短。像 纯CSS3实现光芒旋转四射的头像动画用CSS制作出绚丽燃烧的火狐狸的方法都是研究别人网站上的技术的收获。

经常访问Facebook,或github.com,或plus.google.com的人会发现,它们翻页时页面并不是全部刷新,只有中间文章部分刷新,而页面头和页面侧边栏不刷新。首先我们要理解为什么它们要这样做,这样做有什么好处。

布局

通常的网站页面都有一个规律,比如我们的WebHek网站,左侧的内容以及页面头部的logo和菜单部分在各个页面上都是一样的,只有中间文章部分的内容会变化。传统的页面里,用户访问每个页面时,这些永远不变的部分会反复重复重新加载——其实完全没必要,既浪费流量资源,又影响页面加载速度,我们真正需要它们只加载一次就行了。

当然,有经验的Web程序员已经说出来了,用Ajax动态加载有变化的部分。当用户点击“下一页”时,我们不是真的翻到下一页,而是后台用Ajax把新内容的HTML拉取到客户端,然后删掉原来的内容部分,填充进新拉取的内容。整个效果跟传统的翻页效果一样,但速度更快,更节省资源,而且可以添加一些特性,比如淡入淡出。

但现在有了另外一个问题。在传统的翻页过程中,你可以看到浏览器的地址栏是相应会变化的,会显示当前页面地址,用户可以拷贝这个地址或加入书签或分享给好友。而Ajax实现的翻页地址栏是没有变化的。还有,在传统的翻页过程中,当用户点击“后退”按钮时,浏览器会从缓存里读取前一页,迅速的显示给用户。而Ajax实现的翻页中,用户点击“后退”按钮时,不知道会后退到哪里,因为页面的地址没有变化, window.history里没有存储任何“前一页”的信息。

前面说了这么多,下面才是本文的重点,如何在不刷新页面的情况下修改页面的URL。也就是,如何既能实现用Ajax加载页面实现翻页,又能让浏览器记录翻页地址历史信息。

程序手工存储 window.history信息

function processAjaxData(answer, url){
     document.getElementById("mycontainer").innerHTML = answer.html;
     document.title = answer.pageTitle;
     window.history.pushState({"html":answer.html,"pageTitle":answer.pageTitle},"", url);
 }

answer.html是我们用Ajax在后台拉取的新页面内容,用它替换了页面上的原内容,并且修改了页面标题。最后一步最重要,把页面信息 pushStatewindow.history里。

而当有浏览者点击浏览器“后退”或“前进”按钮时,我们用下面的代码来响应用户的操作:

window.onpopstate = function(event){
    if(event.state){
        document.getElementById("mycontainer").innerHTML = event.state.html;
        document.title = event.state.pageTitle;
    }
};

谷歌浏览器,火狐浏览器,Safafi浏览器、IE10+等现代浏览器都支持这种技术,你也试试吧。

黑客获取数据信息的目的和进攻手段

$
0
0



进入微软、亚马逊,谷歌等美国IT企业工作人才项目,起薪40万,百度搜索(MUMCS)

黑客使用进攻取证获取凭证,如用户名和密码。这些都允许他们访问敏感数据同时能够隐瞒自己的身份,以拖延攻击时被发现的时间并避免暴露自己的行踪。黑客寻找这种以半永久记忆的形式获取存在如 RAM 内存或交换文件中的动态/非静态数据。一旦黑客获得暂时存储在明文中的用户 ID 和密码,他们就可以进入下一个等级的访问,进一步获取资源,如内部网站、文档管理系统和 SharePoint 站点,本文来自网届网。

以下为原文:

“一般来讲,黑客执行下一步的网络攻击都需要非静态数据,而进攻取证是一种捕获这种非静态数据的黑客攻击技术,”计算机取证和电子搜索公司 LLC 伯克利分校研究小组的首席研究员 Joe Sremack 表示。

在进攻取证过程中,黑客捕捉内存中的非静态数据用以获取密码、加密密钥以及活跃网络会话数据,这些都可以帮助他们不受任何限制地访问宝贵数据资源。

为了说明这一点,举一个进攻取证攻击的简单例子。进攻取证攻击过成功中黑客会捕捉 Windows 剪贴板,这是一个不够精明的企业网络用户经常复制和粘贴安全密码的地方。黑客通常利用 Flash 的漏洞来展开这种类型的攻击。

“黑客往往利用浏览器中的 Flash 插件结合较弱的甚至错误的配置来读取浏览器的完整信息,包括内存中的密码,”Sremack 说。

安全意识是击败进攻取证的第一步,技巧和战术、及时的行动是第二步。

目的和手段

黑客使用进攻取证获取凭证,如用户名和密码。这些都允许他们访问敏感数据同时能够隐瞒自己的身份,以拖延攻击时被发现的时间并避免暴露自己的行踪。

“他们还想延长时间,以便于其在被发现之前有充足的时间去访问系统和目标数据,从而增加其犯罪所得,” 安全和风险管理公司 Neohapsis 的首席安全顾问 Scott Hazdra 说。

黑客寻找这种以半永久记忆的形式获取存在如 RAM 内存或交换文件中的动态/非静态数据。

“Windows 临时文件、Windows 或 Mac 的剪贴板、从一个 Telnet 或 FTP 应用程序中未加密的登录数据,和 web 浏览器缓存等都是非静态数据目标,”Sremack 说。

一旦黑客获得暂时存储在明文中的用户 ID 和密码,他们就可以进入下一个等级的访问,进一步获取资源,如内部网站、文档管理系统和 SharePoint 站点,Sremack 解释道。

“这基本上是一个黑客必须使用键盘记录器才能够检索到的信息的途径,但没有键盘记录器,”Sremack 说。

这对于黑客来说极为重要,因为反病毒和反恶意软件工具可以检测并移除键盘记录。黑客们则运行其他的各种工具,比如查看剪贴板、注册表或者电脑用明文存储这些数据的任何工具。

这些工具,为黑客实时进行这些进攻时成为一件免费的福利,并且极容易接入互联网。虽然 Linux 上有工具,但是通常犯这种典型错误(以明文将密码储存在剪贴板)的人使在工作站的终端使用者进行攻击取证成为可能,而这些使用者通常运行 Windows 和 Mac 操作系统。

一些黑客使用特定的工具包括脚本工具作为取证的利器。

“还有大范围用于此用途的各样其他工具,包括免费的和高价的,比如 FTK 成像仪、RedLine、Volatility、CAINE 和 HELIX3 ”,Hazdra 说。

企业响应

“进攻取证很难计数,因为攻击目标机器中的文件可能是安全的,而且传统标准也将宣布系统是安全的,但是入侵者却能够访问机器并能捕捉内存,”Sremack 说。

对付进攻取证的方法包括运行能够掩藏和保护内存数据的安全功能。这些类型的应用程序包括 KeePass 和 KeeScrambler。KeePass 是一个加密的剪贴板工具,能够自动清除剪贴板历史,KeeScrambler 则加密浏览历史。

“每当用户将字母键入浏览器,系统就会加密以防止黑客读取储存在内存中的数据,”Sremack 解释道。目前有免费版的 KeeScrambler,同样能对付键盘记录程序的还有付费版本。

最佳实践要求一个企业网络用户必须在一个特定的机器上登陆进行系统活动,这样一来,黑客就更难以消除自己的行踪。此外,企业应该使用文件系统可仅标记文件为“附录”的特性(不会删除或覆盖现有的数据),这样即使是那台特定机器的系统管理员都无权删除所写,除非机器进入离线维护模式,Lancope 的首席技术官 TK Keanini 这样解释道。

放眼大局来看,企业必须做足充分准备,以针对进攻取证袭击作出有效的事件响应。一个企业应该从三个等级做好救援事件响应准备,Keanini 说,每一个等级需要添加一个维度来补充上一个等级力所不及的。

“即使攻击者可以规避其中的一个等级,他们还是终将暴露在其他等级中,“Keanini 说。

第一个等级是端点遥测。每个端点应该有一些负责操作整个设备的系统级程序。

“虽然你永远不能做到 100% 的准确率,然而百分之零的准确率是绝对不可接受的,”Keanini 说。

第二个等级是网关和接入点遥测。在网络的入口和出口上,一些技术应该记录入站和出站连接。这将为网络互联提供检测和网络取证的依据。

第三个等级是基础设施遥测。

“所有的网络基础设施应该展示未取样的 Netflow/IPFIX(流量分析 /互联网协议流信息输出),”Keanini 认为,IT 安全利用跟踪所有元数据水平下网络流量的工具来收集这些数据集。

“这个数据集作为网络的总帐目,能够提供给你网络中最完整的活动列表,”Keanini 说。

如果一个企业用三个等级的遥测技术来武装其自身安全,几乎没有任何攻击或者攻击者可以找到藏身之处。

Keanini 认为,“更重要的是,当黑客进行某种形式的数据挖掘时,在执行其他阶段的攻击时其仍然要想方设法地去掩藏自己。”

在运营阶段,企业可以发现具备这些遥测水平的攻击者,并在黑客完成进攻目标之前做出相应部署。

企业需要时刻留意进攻取证,它像其他攻击技术一样将持续发展进化。进行网络犯罪的黑客将使用一切可能的工具来完成网络进攻,即使该工具本身是良性的,网络黑客也会背离其设计者的初衷而在犯罪过程中歪曲地使用它。

首席安全官和首席信息安全官们需要不断对其 IT 团队和安全团队进行技术培训,来让他们知晓当前的最新威胁及破解途径。大多数 IT 安全团队最终还是需要最新的工具来检测进攻取证攻击的,Hazdra 说。

高价值资产需要最先进的保护模式,以便安全团队能够检测威胁并防止黑客利用取证工具窃取企业数据,Hazdra 认为。

“未经授权使用这些工具的情况很可能发生于大多数企业和组织网络管理的盲区。因为管理员会监控包括网络流量、文件完整性、入侵检测和未经授权的访问尝试等在内的行为,却没有适当的工具来检测系统上执行内存转储的人或者其安全团队是否在使用进攻取证工具,”Hazdra 解释道。

作者:u014539179 发表于2014-5-16 11:44:42 原文链接
阅读:115 评论:0 查看评论

Web基础架构:负载均衡和LVS

$
0
0

作者:王晨纯

阿里巴巴 Java 开发工程师,目前负责天猫和淘宝的店铺浏览系统,长期关注系统稳定性、性能优化、Web 系统架构。(Blog: blog.hesey.net新浪微博: Hesey 小纯纯

在大规模互联网应用中,负载均衡设备是必不可少的一个节点,源于互联网应用的高并发和大流量的冲击压力,我们通常会在服务端部署多个无状态的应用服务器和若干有状态的存储服务器(数据库、缓存等等)。

一、负载均衡的作用

负载均衡设备的任务就是作为应用服务器流量的入口,挑选最合适的一台服务器,将客户端的请求转发给它处理,实现客户端到真实服务端的透明转发。最近几年很火的「云计算」以及分布式架构,本质上也是将后端服务器作为计算资源、存储资源,由某台管理服务器封装成一个服务对外提供,客户端不需要关心真正提供服务的是哪台机器,在它看来,就好像它面对的是一台拥有近乎无限能力的服务器,而本质上,真正提供服务的,是后端的集群。

一个典型的互联网应用的拓扑结构是这样的:

二、负载均衡的类型

负载均衡可以采用硬件设备,也可以采用软件负载。

商用硬件负载设备成本通常较高(一台几十万上百万很正常),所以在条件允许的情况下我们会采用软负载,软负载解决的两个核心问题是:选谁、转发,其中最著名的是 LVS(Linux Virtual Server)。

三、软负载——LVS

LVS 是四层负载均衡,也就是说建立在 OSI 模型的第四层——传输层之上,传输层上有我们熟悉的 TCP/UDP,LVS 支持 TCP/UDP 的负载均衡。

LVS 的转发主要通过修改 IP 地址(NAT 模式,分为源地址修改 SNAT 和目标地址修改 DNAT)、修改目标 MAC(DR 模式)来实现。

那么为什么 LVS 是在第四层做负载均衡?

首先 LVS 不像 HAProxy 等七层软负载面向的是 HTTP 包,所以七层负载可以做的 URL 解析等工作,LVS 无法完成。其次,某次用户访问是与服务端建立连接后交换数据包实现的,如果在第三层网络层做负载均衡,那么将失去「连接」的语义。软负载面向的对象应该是一个已经建立连接的用户,而不是一个孤零零的 IP 包。后面会看到,实际上 LVS 的机器代替真实的服务器与用户通过 TCP 三次握手建立了连接,所以 LVS 是需要关心「连接」级别的状态的。

LVS 的工作模式主要有 4 种:

DR

NAT

TUNNEL

Full-NAT

这里挑选常用的 DR、NAT、Full-NAT 来简单介绍一下。

1、DR

请求由 LVS 接受,由真实提供服务的服务器(RealServer, RS)直接返回给用户,返回的时候不经过 LVS。

DR 模式下需要 LVS 和绑定同一个 VIP(RS 通过将 VIP 绑定在 loopback 实现)。

一个请求过来时,LVS 只需要将网络帧的 MAC 地址修改为某一台 RS 的 MAC,该包就会被转发到相应的 RS 处理,注意此时的源 IP 和目标 IP 都没变,LVS 只是做了一下移花接木。

RS 收到 LVS 转发来的包,链路层发现 MAC 是自己的,到上面的网络层,发现 IP 也是自己的,于是这个包被合法地接受,RS 感知不到前面有 LVS 的存在。

而当 RS 返回响应时,只要直接向源 IP(即用户的 IP)返回即可,不再经过 LVS。

DR 模式是性能最好的一种模式。

2、NAT

NAT(Network Address Translation)是一种外网和内网地址映射的技术。

NAT 模式下,网络报的进出都要经过 LVS 的处理。LVS 需要作为 RS 的网关。

当包到达 LVS 时,LVS 做目标地址转换(DNAT),将目标 IP 改为 RS 的 IP。RS 接收到包以后,仿佛是客户端直接发给它的一样。

RS 处理完,返回响应时,源 IP 是 RS IP,目标 IP 是客户端的 IP。

这时 RS 的包通过网关(LVS)中转,LVS 会做源地址转换(SNAT),将包的源地址改为 VIP,这样,这个包对客户端看起来就仿佛是 LVS 直接返回给它的。客户端无法感知到后端 RS 的存在。

3、Full-NAT

无论是 DR 还是 NAT 模式,不可避免的都有一个问题:LVS 和 RS 必须在同一个 VLAN 下,否则 LVS 无法作为 RS 的网关。

这引发的两个问题是:

1、同一个 VLAN 的限制导致运维不方便,跨 VLAN 的 RS 无法接入。

2、LVS 的水平扩展受到制约。当 RS 水平扩容时,总有一天其上的单点 LVS 会成为瓶颈。

Full-NAT 由此而生,解决的是 LVS 和 RS 跨 VLAN 的问题,而跨 VLAN 问题解决后,LVS 和 RS 不再存在 VLAN 上的从属关系,可以做到多个 LVS 对应多个 RS,解决水平扩容的问题。

Full-NAT 相比 NAT 的主要改进是,在 SNAT/DNAT 的基础上,加上另一种转换,转换过程如下:

在包从 LVS 转到 RS 的过程中,源地址从客户端 IP 被替换成了 LVS 的内网 IP。

内网 IP 之间可以通过多个交换机跨 VLAN 通信。

当 RS 处理完接受到的包,返回时,会将这个包返回给 LVS 的内网 IP,这一步也不受限于 VLAN。

LVS 收到包后,在 NAT 模式修改源地址的基础上,再把 RS 发来的包中的目标地址从 LVS 内网 IP 改为客户端的 IP。

Full-NAT 主要的思想是把网关和其下机器的通信,改为了普通的网络通信,从而解决了跨 VLAN 的问题。采用这种方式,LVS 和 RS 的部署在 VLAN 上将不再有任何限制,大大提高了运维部署的便利性。

4、Session

客户端与服务端的通信,一次请求可能包含多个 TCP 包,LVS 必须保证同一连接的 TCP 包,必须被转发到同一台 RS,否则就乱套了。为了确保这一点,LVS 内部维护着一个 Session 的 Hash 表,通过客户端的某些信息可以找到应该转发到哪一台 RS 上。

5、LVS 集群化

采用 Full-NAT 模式后,可以搭建 LVS 的集群,拓扑结构如下图:

6、容灾

容灾分为 RS 的容灾和 LVS 的容灾。

RS 的容灾可以通过 LVS 定期健康检测实现,如果某台 RS 失去心跳,则认为其已经下线,不会在转发到该 RS 上。

LVS 的容灾可以通过主备+心跳的方式实现。主 LVS 失去心跳后,备 LVS 可以作为热备立即替换。

容灾主要是靠 KeepAlived 来做的。

更多参考资料: 吴佳明 – LVS 在大规模网络环境下的应用 – O’Reilly Velocity China 2012

本文链接

为什么我说在中国“秘密”必死?

$
0
0


在中国,秘密难成商业模式,必死,除了炒作一把外,没有任何价值。

为什么这么说?难倒像我这样做竞争情报的不喜欢爆料吗?

其实爆料,谁都喜欢,但“秘密”就是不可能存在下去。我可以在微博爆料,但不能在秘密爆料。

第一,我在微博爆料,是可控的,虽然运营商都要求实名注册,但由于实名级别并不高,因此还是可以在一定程度匿名的情况下发布信息的。

第二,爆料的目的是什么,其实爆料本就是为了发泄,为了传播,否则自己找个地方泻泻火,如健身房,或找朋友去吐吐苦水,就可以了。

第三,有人说,我爆料是为了造成混乱,又可以隐藏身份。那么你选择“秘密”一定错了,不猛的料,在“秘密”这样的环境传不远,而如果料猛了,你会对信息失控,更要命的是,你以为“秘密”的运营商会为你保守秘密吗?你做梦吧。

第四,运营者如何维持“秘密”的活跃度,必然自己往里面“灌料”,这些料谁保证真实性?没有!

第五,运营者遇上监管部门会如何,想想就知道。

第六,在“秘密”上发了秘密后安全吗?想想,你有没有什么把柄在运营者手里?

其实,“秘密”在国内IT圈早已出现过,而且不只一个,现在怎么样了?如果不是90后的话,不要说你不知道是哪个。

最后,想爆料,还是到微博吧,只要能吸引眼球,内容自己就会被段子手拿走,在微博、微信中传播,而且别人还不知道你是谁,也很少有人追查(有反竞争情报意识的话,追查也难,除非你把爆料当职业)。

  青春就应该这样绽放   游戏测试:三国时期谁是你最好的兄弟!!   你不得不信的星座秘密

毕业论文相关PPT资料整理

$
0
0

如果需要毕业论文PPT答辩模板,请看看这里收集的资料有没有你需要的:

2014年5月16日 增加

天蓝色汇报汇报答辩模板: http://dl.vmall.com/c08k02a6fg

1、 10年1月,我自己的毕业论文答辩PPThttp://www.qiexing.com/post/1282.html

2、 09年5月整理的毕业论文答辩PPT材料 http://www.qiexing.com/post/1116.html

3、今天整理的毕业论文答辩资源:

刘青11-YY.ppt   
刘青14-ST.ppt   
我的毕业论文答辩.ppt   
原创硕士答辩PPT.ppt   
文史类论文模板.pot   
通用版本(墨绿风格).pot   
理工类论文模板.pot   
毕业论文公开答辩稿.ppt   
北京邮电大学.ppt   
MBA论文答辩报告.ppt   
论文答辩.pps   
Female Authority and Narrative Voice.ppt   
孙方答辩-修改.ppt   

 下载地址http://www.qiexing.com/post/cai-use-powerpoint.html(前链接地址失效 资料正在整理)

《毕业论文相关PPT资料整理》Copyright © 且行 教育技术:欢迎复制-转载-传播

继续阅读《毕业论文相关PPT资料整理》的全文内容...

分类: 教育技术研究 | Tags: PPT   PowerPoint   论文   | 添加评论(1)

相关文章:

公安部:“6年免检”实为“6年免上线检验”

$
0
0
【“6年免检”实为“6年免上线检验”】今年9月起试行非营运轿车6年内免上线检验。公安部提请注意,法律规定未作修改,这是过渡性改革措施,非营运轿车检验周期未发生变化,仅是试行6年内免予上线检验。车主仍需每2年向公安交管部门申领一次检验标志,但无需到检验机构检验。 ......

iOS应用崩溃日志揭秘

$
0
0

转自  http://www.raywenderlich.com/zh-hans/30818/ios应用崩溃日志揭秘

 

 

本文作者是  Soheil Moayedi Azarpour, 他是一名独立iOS开发者。


作为一名应用开发者,你是否有过如下经历?

Learn how to make sense of crash logs!
为确保你的应用正确无误,在将其提交到应用商店之前,你必定进行了大量的测试工作。它在你的设备上也运行得很好,但是,上了应用商店后,还是有用户抱怨会闪退 !
如果你跟我一样是个完美主义者,你肯定想将应用做到尽善尽美。于是你打开代码准备修复闪退的问题……但是,从何处着手呢?
这时iOS崩溃日志派上用场了。在大多数情况下,你能从中了解到关于闪退的详尽、有用的信息。
通过本教程,你将学习到一些常见的崩溃日志案例,以及如何从开发设备和iTunes Connect上获取崩溃日志文件。你还将学习到符号化( symbolication),从日志追踪到代码 。你还将学习调试一个在待定情况下会闪退的应用。
让我们开始动手吧!

什么是崩溃日志,从哪里能得它?

iOS设备上的应用闪退时,操作系统会生成一个崩溃报告,也叫崩溃日志,保存在设备上。
崩溃日志上有很多有用的信息,包括应用是什么情况下闪退的。通常,上面有每个正在执行线程的完整堆栈跟踪信息,所以你能从中了解到闪退发生时各线程都在做什么,并分辨出闪退发生在哪个线程上。
有几种方法可以从设备上获取崩溃日志。
设备与电脑上的iTunes Store同步后,会将崩溃日志保存在电脑上。根据电脑操作系统的不同,崩溃日志将保存在以下位置:
Mac OS X:

 

~/Library/Logs/CrashReporter/MobileDevice/

Windows XP:

 

 

C:Documents and Settings<USERNAME>Application DataApple ComputerLogsCrashReporterMobileDevice<DEVICE_NAME>

 

 

Windows Vista or 7:

C:Users<USERNAME>AppDataRoamingApple ComputerLogsCrashReporterMobileDevice<DEVICE_NAME>

当用户抱怨闪退时,你可以要求他让设备与iTunes同步,并根据操作系统的不同,到上述位置把崩溃日志下载下来,然后通过电子邮件发送给你。
你必需尽量获取用户设备生成的所有崩溃日志。因为崩溃日志越多,就越容易诊断问题所在!
另外,如果你装了Xcode,也能很容易通过Xcode从你的设备上获得崩溃日志。将iOS设备连接到电脑上,然后打开Xcode。从菜单栏上选择  Window  菜单, 然后选择  Organizer (快捷方式是 Shift-CMD-2).
在 Organizer 窗口上, 选中  Devices 标签栏. 在左侧的导航面板上,选中  Device Logs, 如下图所示:
Devices tab in Xcode Organizer
看看上图,左侧有好几个 Device Logs 菜单项.  LIBRARY 下面的Device Logs是你所有设备(曾经连接到Xcode的)的日志 。每个设备下面的 Device Logs 是对应设备的日志。
应用提交到App Store后,你也能从  iTunes Connect 获取到用户的崩溃日志. 登录到 iTunes Connect 上, 选择 Manage Your Applications, 点击相应的应用, 点击应用图标下面的  View Details 按钮, 然后点击右栏Links部分的   Crash Reports 。
Crash Reports in iTunes Connect
如果没有崩溃日志,试试点击 Refresh 按钮刷新一下。如果你的应用还卖得不多,或者刚上架不久,iTunes Connect账号上也可能还没有任何崩溃日志。
如果iTunes Connect上有崩溃日志,你将看到如下图:
Crash Reports in iTunes Connect
有时,尽管有用户报告闪退,你仍然看不到崩溃报告。这时,最好让用户直接把崩溃报告发送给你。

什么情况下会产生崩溃日志?

两种主要情况会产生崩溃日志:

  1. 应用违反操作系统规则。
  2. 应用中有Bug。

违反iOS规则包括在启动、恢复、挂起、退出时watchdog超时、用户强制退出和低内存终止。让我们详细了解一下吧。
Watchdog 超时机制
从iOS 4.x开始,退出应用时,应用不会立即终止,而是退到后台。
但是,如果你的应用响应不够快,操作系统有可能会终止你的应用,并产生一个崩溃日志。这些事件与下列UIApplicationDelegate方法相对应:

  • application:didFinishLaunchingWithOptions:
  • applicationWillResignActive:
  • applicationDidEnterBackground:
  • applicationWillEnterForeground:
  • applicationDidBecomeActive:
  • applicationWillTerminate:

上面所有这些方法,应用只有有限的时间去完成处理。如果花费时间太长,操作系统将终止应用。

注意: 如果你没有把需要花费时间比较长的操作(如网络访问)放在后台线程上就很容易发生这种情况。关于如果避免这种情况的信息,请参考我们的另外两篇教程:  Grand Central Dispatch 和  NSOperations

用户强制退出
iOS 4.x开始支持多任务。如果应用阻塞界面并停止响应, 用户可以通过在主屏幕上双击Home按钮来终止应用。此时,操作应用将生成一个崩溃日志。

注意: 双击Home按钮后,你将看到运行过的所有应用。那些应用不一定是正在运行,也不一定是被挂起。
通常,用户点击Home按钮时,应用将在后台保留约10分钟,然后操作系统自动将其终止。 所以双击Home按钮显示的应用列表只是表明那是一系列过去打开过的应用。删除那些应用的图标不会产生任何崩溃日志。

低内存终止
子类化UIViewController时,你或许已经注意到 didReceiveMemoryWarning方法。
在前台运行的应用拥有访问和使用内存的最高优化级。然而,这并不意味着该应用能使用设备的所有可用内存 ——每个应用只能使用一部分可用内存。
当内存使用达到一定程度时,操作系统将发出一个  UIApplicationDidReceiveMemoryWarningNotification 通知。同时,调用  didReceiveMemoryWarning 方法。
此时,为了让应用继续正常运行,操作系统开始终止在后台的其他应用以释放一些内存。所有后台应用被终止后,如果你的应用还需要更多内存,操作系统会将你的应用也终止掉,并产生一个崩溃日志。而在这种情况下被终止的后台应用,不会产生崩溃日志。

注意: 根据  苹果文档, Xcode不会自动添加低内存日志。你必需手动获取日志。 然而,根据我的个人经验,使用 Xcode 4.5.2, 低内存日志也会自动导入,只是”Process”和”Type”属性都被标为Unknown(未知)。
另外,值得一提的是在极短时间内分配一大块内存将给系统内存带来巨大负担。这样,也会产生内存警告的通知。

应用中有Bug
如你所想,大多数闪退都是由于应用中有Bug,因此大多数崩溃日志的产生都是因为应用中的Bug。Bug的种类的有很多。

在本教程的后半部分,你将通过调试一个会产生崩溃日志的含有Bug的应用,学习如何找到问题所在并进行修复!

崩溃日志的实例

让我们看看一个崩溃日志的实例,以使你在处理一些实际问题之前心里有谱。
事不宜迟,见见你的新朋友吧:

 
[objc]  view plaincopy
 
  1. // 1: 进程信息  

Incident Identifier: 30E46451-53FD-4965-896A-457FC11AD05F
CrashReporter Key:   5a56599d836c4f867f6eec76afee451bf9ae5f31
Hardware Model:      iPhone4,1
Process:         Rage Masters [4155]
Path:            /var/mobile/Applications/A5635B22-F5EF-4CEB-94B6-FE158D885014/Rage Masters.app/Rage Masters
Identifier:      Rage Masters
Version:         ??? (???)
Code Type:       ARM (Native)
Parent Process:  launchd [1]
// 2: 基本信息
Date/Time:       2012-10-17 21:39:06.967 -0400
OS Version:      iOS 6.0 (10A403)
Report Version:  104
// 3: 异常
Exception Type:  00000020
Exception Codes: 0x000000008badf00d
Highlighted Thread:  0
// 4: 线程回溯
Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0:
0   libsystem_kernel.dylib            0x327f2eb4 mach_msg_trap + 20
1   libsystem_kernel.dylib            0x327f3048 mach_msg + 36
2   CoreFoundation                    0x36bd4040 __CFRunLoopServiceMachPort + 124
3   CoreFoundation                    0x36bd2d9e __CFRunLoopRun + 878
4   CoreFoundation                    0x36b45eb8 CFRunLoopRunSpecific + 352
5   CoreFoundation                    0x36b45d44 CFRunLoopRunInMode + 100
6   CFNetwork                         0x32ac343e CFURLConnectionSendSynchronousRequest + 330
7   Foundation                        0x346e69ba +[NSURLConnection sendSynchronousRequest:returningResponse:error:] + 242
8   Rage Masters                      0x000d4046 0xd2000 + 8262
Thread 1:
0   libsystem_kernel.dylib            0x32803d98 __workq_kernreturn + 8
1   libsystem_c.dylib                 0x3a987cf6 _pthread_workq_return + 14
2   libsystem_c.dylib                 0x3a987a12 _pthread_wqthread + 362
3   libsystem_c.dylib                 0x3a9878a0 start_wqthread + 4
// 5: 线程状态
Thread 0 crashed with ARM Thread State (32-bit):
    r0: 0x00000000    r1: 0x00000000      r2: 0x00000001      r3: 0x39529fc8
    r4: 0xffffffff    r5: 0x2fd7d301      r6: 0x2fd7d300      r7: 0x2fd7d9d0
    r8: 0x2fd7d330    r9: 0x3adbf8a8     r10: 0x2fd7d308     r11: 0x00000032
    ip: 0x00000025    sp: 0x2fd7d2ec      lr: 0x001bdb25      pc: 0x30301838
  cpsr: 0x00000010
// 6: 二进制映像
Binary Images:
0xd2000 -    0xd7fff +Rage Masters armv7   /var/mobile/Applications/A5635B22-F5EF-4CEB-94B6-FE158D885014/Rage Masters.app/Rage Masters
0x2fe41000 - 0x2fe61fff  dyld armv7   /usr/lib/dyld
0x327f2000 - 0x32808fff  libsystem_kernel.dylib armv7   /usr/lib/system/libsystem_kernel.dylib
0x328a8000 - 0x328bdfff  libresolv.9.dylib armv7   /usr/lib/libresolv.9.dylib
0x32a70000 - 0x32b35fff  CFNetwork armv7   /System/Library/Frameworks/CFNetwork.framework/CFNetwork
0x32b7a000 - 0x32cc3fff  libicucore.A.dylib armv7   /usr/lib/libicucore.A.dylib
0x32cc4000 - 0x32cc5fff  CoreSurface armv7   /System/Library/PrivateFrameworks/CoreSurface.framework/CoreSurface
0x32f65000 - 0x32f8afff  OpenCL armv7   /System/Library/PrivateFrameworks/OpenCL.framework/OpenCL

 

这报告看起来像天书。:) 我们分几部分来解读吧:

(1) 进程信息
第一部分是闪退进程的相关信息。

  • Incident Identifier是崩溃报告的唯一标识符。
  • CrashReporter Key 是与设备标识相对应的唯一键值。虽然它不是真正的设备标识符,但也是一个非常有用的情报:如果你看到100个崩溃日志的CrashReporter Key值都是相同的,或者只有少数几个不同的CrashReport值,说明这不是一个普遍的问题,只发生在一个或少数几个设备上。
  • Hardware Model 标识设备类型。 如果很多崩溃日志都是来自相同的设备类型,说明应用只在某特定类型的设备上有问题。上面的日志里,崩溃日志产生的设备是iPhone 4s。
  • Process 是应用名称。中括号里面的数字是闪退时应用的进程ID。
  • 接下来几行不言自明,无需赘述。

(2) 基本信息
这部分给出了一些基本信息,包括闪退发生的日期和时间,设备的iOS版本。如果有很多崩溃日志都来自iOS 6.0,说明问题只发生在iOS 6.0上。
(3) 异常
在这部分,你可以看到闪退发生时抛出的异常类型。还能看到异常编码和抛出异常的线程。根据崩溃报告类型的不同,在这部分你还能看到一些另外的信息。
(4) 线程回溯
这部分提供应用中所有线程的回溯日志。 回溯是闪退发生时所有活动帧清单。它包含闪退发生时调用函数的清单。看下面这行日志:

 

 

2    XYZLib    0x34648e88    0x83000 + 8740

 

它包括四列:

  1. 帧编号—— 此处是2。
  2. 二进制库的名称 ——此处是 XYZLib.
  3. 调用方法的地址 ——此处是 0x34648e88.
  4. 第四列分为两个子列,一个基本地址和一个偏移量。此处是0×83000 + 8740, 第一个数字指向文件,第二个数字指向文件中的代码行。

(5) 线程状态
这部分是闪退时寄存器中的值。一般不需要这部分的信息,因为回溯部分的信息已经足够让你找出问题所在。
(6) 二进制映像
这部分列出了闪退时已经加载的二进制文件。

符号化Symbolication

第一次看到崩溃日志上的回溯时,你或许会觉得它没什么意义。我们习惯使用方法名和行数,而非像这样的神秘位置:

 

 

 

6    Rage Masters    0x0001625c    0x2a000 + 3003

 

将这些十六进制地址转化成方法名称和行数的过程称之为符号化。
从Xcode的Organizer窗口获取崩溃日志后过几秒钟,崩溃日志将被自动符号化。上面那行被符号化后的版本如下 :

 

 

 

6    Rage Masters    0x0001625c    -[RMAppDelegate application:didFinishLaunchingWithOptions:] (RMAppDelegate.m:35)

 

Xcode符号化崩溃日志时,需要访问与App Store上对应的应用二进制文件以及生成二进制文件时产生的  .dSYM 文件。必需完全匹配才行。否则,日志将无法被完全符号化。
所以,保留每个分发给用户的编译版本非常重要。提交应用前进行归档时,Xcode将保存应用的二进制文件。可以在Xcode Organizer的Archives标签栏下找到所有已归档的应用文件。
在发现崩溃日志时,如果有相匹配的.dSYM文件和应用二进制文件,Xcode会自动对崩溃日志进行符号化。如果你换到别的电脑或创建新的账户,务必将所有二进制文件移动到正确的位置,使Xcode能找到它们。

注意: 你必需同时保留应用二进制文件和.dSYM文件才能将崩溃日志完整符号化。每次提交到iTunes Connect的构建都必需归档。
.dSYM文件和二进制文件是特定绑定于每一次构建和后续构建的,即使来自相同的源代码文件,每一次构建也与其他构建不同,不能相互替换。
如果你使用Build 和 Archive 命令,这些文件会自动放在适当位置。 如果不是使用Build 和 Archive命令,放在Spotlight能够搜索到的位置(比如Home目录)即可。

 

低内存闪退

因为低内存崩溃日志与普通崩溃日志略有不同,所以本教程特别分开说明一下。:]
iOS设备检测到低内存时,虚拟内存系统发出通知请求应用释放内存。这些通知发送到所有正在运行的应用和进程,试图收回一些内存。
如果内存使用依然居高不下,系统将会终止后台线程以缓解内存压力。如果可用内存足够,应用将能够继续运行而不会产生崩溃报告。否则,应用将被iOS终止,并产生低内存崩溃报告。
低内存崩溃日志上没有应用线程的堆栈回溯。相反,上面显示的是以内存页数为单位的各进程内存使用量。(在撰写本文的时候,一个内存页的大小是4KB。)
被iOS因释放内存页终止的进程名称后面你会看到 jettisoned 字样。如果看到它出现在你的应用名称后面,说明你的应用因使用太多内存而被终止了。
低内存崩溃日志看起来像这样:

 

 

 

Incident Identifier: 30E46451-53FD-4965-896A-457FC11AD05F
CrashReporter Key:   5a56599d836c4f867f6eec76afee451bf9ae5f31
OS Version:          iPhone OS 3.1.3 (7E18)
Date/Time:           2012-10-17 21:39:06.967 -0400
Free pages:        96
Wired pages:       10558
Purgeable pages:   0
Largest process:   Rage Masters
Processes
         Name                 UUID                    Count resident pages
    Rage Masters     9320 (jettisoned) (active)
    mediaserverd      255
     dataaccessd      505
         syslogd       71
            apsd      171
       securityd      243
         notifyd     2027
      CommCenter      189
     SpringBoard     2158 (active)
      accessoryd       91
         configd      371
       fairplayd       93
   mDNSResponder      292
       lockdownd     1204
         launchd       72

 

当应用发生低内存闪退时,你必需看看应用中内存使用的方式,以及是如何处理低内存警告的。你可以使用Instruments工具中使用Allocations 和 Leaks来发现内存分配问题和内存泄漏问题。如果你不知道如何利用 Instruments 检查内存问题,可以看看 这个教程 。
还有,别忘记虚拟内存! Instruments工具的Leaks 和 Allocations 不能跟踪显存使用情况。必需使用 VM Tracker 才能查看显存使用情况。
VM Tracker 默认是关闭的。打开Instrument,手动 选中 Automatic Snapshotting 标志或者按下 Snapshot Now 按钮。
本教程后面将会学习如何研究低内存崩溃日志。

异常编码

在研究真实闪退场景之前,还有一点需要重点介绍一下:就是那些有趣的异常编码 。
你可以在报告的异常部分——前面代码的第3部分找到异常编码。有些编码比较常见。
通常,异常编码以一些文字开头,紧接着是一个或多个十六进制值,此数值正是说明闪退根本性质的所在。  从这些编码中,可以区分出闪退是因为程序错误、非法内存访问或者是其他原因。
下面是一些常见的异常编码:

  • 0x8badf00d: 读做 “ate bad food”! (把数字换成字母,是不是很像 :p)该编码表示应用是因为发生watchdog超时而被iOS终止的。  通常是应用花费太多时间而无法启动、终止或响应用系统事件。

  • 0xbad22222: 该编码表示 VoIP 应用因为过于频繁重启而被终止。
  • 0xdead10cc: 读做 “dead lock”!该代码表明应用因为在后台运行时占用系统资源,如通讯录数据库不释放而被终止 。
  • 0xdeadfa11: 读做 “dead fall”! 该代码表示应用是被用户强制退出的。根据苹果文档, 强制退出发生在用户长按开关按钮直到出现 “滑动来关机”, 然后长按 Home按钮。强制退出将产生 包含0xdeadfa11 异常编码的崩溃日志, 因为大多数是强制退出是因为应用阻塞了界面。

 

注意: 在后台任务列表中关闭已挂起的应用不会产生崩溃日志。 一旦应用被挂起,它何时被终止都是合理的。所以不会产生崩溃日志。

大展身手的时候到了!

好了! 你已经学习了所有分析崩溃日志和修复错误的基础知识!
假设你刚进入Rage-O-Rage有限公司工作。该公司有一个在App Store上热销的应用,叫 Rage Masters。
你的老板安迪要你帮忙解决几个用户经常抱怨闪退问题。你的任务就是研究这些闪退,符号化用户提供的崩溃日志,查找问题所在,并修复之。
你可以从  这里下载应用的源代码。

注意: 如果你想自己重新生成崩溃报告,请遵照以下指引:

  1. 下载源码然后在Xcode中打开工程文件。
  2. 使用正确的provisioning profile连接到iOS设备。
  3. 从Xcode工具栏上选择iOS设备——不是模拟器作为target,然后构建应用。
  4. 当你在设备上到默认页面(应用的全屏图片)时,立即在Xcode上点击停止按钮。
  5. 关闭 Xcode。
  6. 在设备上直接打开应用。
  7. 测试场景,完成后连接设备到电脑上,通过Xcode获取崩溃日志。

 

场景 1: 糟糕的代码

一封来自用户的邮件: “大哥,你的应用就是一坨屎! 我将其下载到我自己的iPod Touch和iPhone上,还下载到我儿子的iPod Touch上。在所有的设备上,都是还没打开就闪退了……”
别一封来自用户的邮件说, “我下载了你们的应用,一打开就闪退。真悲催…”
另一封邮件说得更明确:”你们的应用不能运行。我把它下载到我和妻子的设备上。所有设备都是 一打开就闪退了…”

好吧,别灰心! 这些意见藏着什么玄机呢?让我们看看崩溃日志吧:

 

 

Incident Identifier: 85833DBA-3DF7-43EE-AF80-4E5C51091F42
CrashReporter Key:   5a56599d836c4f867f6eec76afee451bf9ae5f31
Hardware Model:      iPhone4,1
Process:         Rage Masters [20067]
Path:            /var/mobile/Applications/B2121A89-3D1F-4E61-BB18-5511E1DC150F/Rage Masters.app/Rage Masters
Identifier:      Rage Masters
Version:         ??? (???)
Code Type:       ARM (Native)
Parent Process:  launchd [1]
Date/Time:       2012-11-03 13:37:31.148 -0400
OS Version:      iOS 6.0 (10A403)
Report Version:  104
Exception Type:  00000020
Exception Codes: 0x000000008badf00d
Highlighted Thread:  0
Application Specific Information:
Soheil-Azarpour.Rage-Masters failed to launch in time
Elapsed total CPU time (seconds): 8.030 (user 8.030, system 0.000), 20% CPU 
Elapsed application CPU time (seconds): 3.840, 10% CPU
Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0:
0   libsystem_kernel.dylib            0x327f2eb4 mach_msg_trap + 20
1   libsystem_kernel.dylib            0x327f3048 mach_msg + 36
2   CoreFoundation                    0x36bd4040 __CFRunLoopServiceMachPort + 124
3   CoreFoundation                    0x36bd2d9e __CFRunLoopRun + 878
4   CoreFoundation                    0x36b45eb8 CFRunLoopRunSpecific + 352
5   CoreFoundation                    0x36b45d44 CFRunLoopRunInMode + 100
6   CFNetwork                         0x32ac343e CFURLConnectionSendSynchronousRequest + 330
7   Foundation                        0x346e69ba +[NSURLConnection sendSynchronousRequest:returningResponse:error:] + 242
8   Rage Masters                      0x000ea1c4 -[RMAppDelegate application:didFinishLaunchingWithOptions:] (RMAppDelegate.m:36)
9   UIKit                             0x37f30ad4 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 248
10  UIKit                             0x37f3065e -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1186
11  UIKit                             0x37f28846 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 694
12  UIKit                             0x37ed0c3c -[UIApplication handleEvent:withNewEvent:] + 1000
13  UIKit                             0x37ed06d0 -[UIApplication sendEvent:] + 68
14  UIKit                             0x37ed011e _UIApplicationHandleEvent + 6150
15  GraphicsServices                  0x370835a0 _PurpleEventCallback + 588
16  GraphicsServices                  0x370831ce PurpleEventCallback + 30
17  CoreFoundation                    0x36bd4170 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 32
18  CoreFoundation                    0x36bd4112 __CFRunLoopDoSource1 + 134
19  CoreFoundation                    0x36bd2f94 __CFRunLoopRun + 1380
20  CoreFoundation                    0x36b45eb8 CFRunLoopRunSpecific + 352
21  CoreFoundation                    0x36b45d44 CFRunLoopRunInMode + 100
22  UIKit                             0x37f27480 -[UIApplication _run] + 664
23  UIKit                             0x37f242fc UIApplicationMain + 1116
24  Rage Masters                      0x000ea004 main (main.m:16)
25  libdyld.dylib                     0x3b630b1c start + 0

 

发现问题了吗? 异常编码是 0x000000008badf00d,还有后面的报告:

 

 

Application Specific Information:
Soheil-Azarpour.Rage-Masters failed to launch in time
Elapsed total CPU time (seconds): 8.030 (user 8.030, system 0.000), 20% CPU 
Elapsed application CPU time (seconds): 3.840, 10% CPU

 

这说明应用在启动时就闪退了,iOS的watchdog机制终止了应用。帅! 找到问题了,但是为什会发生这样的事呢?
接着往下看日志。 从下向上读回溯日志。最底下的帧 (frame 25: libdyld.dylib)是最先调用的,然后是帧24, Rage Masters, main (main.m:16) ,依此类推。
跟应用源代码相关的帧是最重要的。忽略掉系统库和框架。下一个与代码相关的帧是:

 

 

8    Rage Masters    0x0009f244 -[RMAppDelegate application:didFinishLaunchingWithOptions:] (RMAppDelegate.m:35)

 

应用在执行RMAppDelegate (RMAppDelegate.m:35)类 application:didFinishLaunchingWithOptions: 方法第35 行代码时闪退。打开Xcode看看那行代码:

 

 

NSData *directoryData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];

 

就是它了! 同步调用web服务?! 在主线程上?! 在  application:didFinishLaunchingWithOptions: 方法上?!! 谁写的代码呀?!

Network calls on the main thread makes kittens sad.

Network calls on the main thread makes kittens sad.

不管如何,问题得你来修复了。这个调用必需异步进行,甚至更理想的情况是,在 application:didFinishLaunchingWithOptions:返回YES之后的其他部分再执行Web服务。
在其他地方调用可能需要比较多的修改。当下,我们只要使应用不闪退就行。可以在日后再实现更好的设计。 将上面那行讨厌的代码(及其下面的三行代码)换成下面这个异步的版本吧:

 

 [NSURLConnection sendAsynchronousRequest:request
                                           queue:[NSOperationQueue mainQueue]
                               completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
         {
             NSURL *cacheDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSUserDirectory inDomains:NSCachesDirectory] lastObject];
             NSURL *filePath = [NSURL URLWithString:kDirectoryFile relativeToURL:cacheDirectory];
             [data writeToFile:[filePath absoluteString] atomically:YES];
         }];

 

场景 2: 无法响应事件的按钮

一名用户说: “我不能将某个rage master添加到书签里面。我想添加的时候应用就闪退…”
用一名用户说 :”书签不能用 … 在详细页面上,点击书签按钮,应用就闪退了!”
上面的抱怨说得不是很清楚,引起问题的原因肯定有多样。看看崩溃日志:

 

 

Incident Identifier: 3AAA63CC-3088-41CC-84D9-82FE03F9F354
CrashReporter Key:   5a56599d836c4f867f6eec76afee451bf9ae5f31
Hardware Model:      iPhone4,1
Process:         Rage Masters [20090]
Path:            /var/mobile/Applications/B2121A89-3D1F-4E61-BB18-5511E1DC150F/Rage Masters.app/Rage Masters
Identifier:      Rage Masters
Version:         ??? (???)
Code Type:       ARM (Native)
Parent Process:  launchd [1]
Date/Time:       2012-11-03 13:39:00.081 -0400
OS Version:      iOS 6.0 (10A403)
Report Version:  104
Exception Type:  EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Crashed Thread:  0
Last Exception Backtrace:
0   CoreFoundation                    0x36bff29e __exceptionPreprocess + 158
1   libobjc.A.dylib                   0x34f0f97a objc_exception_throw + 26
2   CoreFoundation                    0x36c02e02 -[NSObject(NSObject) doesNotRecognizeSelector:] + 166
3   CoreFoundation                    0x36c0152c ___forwarding___ + 388
4   CoreFoundation                    0x36b58f64 _CF_forwarding_prep_0 + 20
5   UIKit                             0x37fbb0a8 -[UIApplication sendAction:to:from:forEvent:] + 68
6   UIKit                             0x37fbb05a -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 26
7   UIKit                             0x37fbb038 -[UIControl sendAction:to:forEvent:] + 40
8   UIKit                             0x37fba8ee -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 498
9   UIKit                             0x37fbade4 -[UIControl touchesEnded:withEvent:] + 484
10  UIKit                             0x37ee35f4 -[UIWindow _sendTouchesForEvent:] + 520
11  UIKit                             0x37ed0804 -[UIApplication sendEvent:] + 376
12  UIKit                             0x37ed011e _UIApplicationHandleEvent + 6150
13  GraphicsServices                  0x3708359e _PurpleEventCallback + 586
14  GraphicsServices                  0x370831ce PurpleEventCallback + 30
15  CoreFoundation                    0x36bd416e __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 30
16  CoreFoundation                    0x36bd4112 __CFRunLoopDoSource1 + 134
17  CoreFoundation                    0x36bd2f94 __CFRunLoopRun + 1380
18  CoreFoundation                    0x36b45eb8 CFRunLoopRunSpecific + 352
19  CoreFoundation                    0x36b45d44 CFRunLoopRunInMode + 100
20  GraphicsServices                  0x370822e6 GSEventRunModal + 70
21  UIKit                             0x37f242fc UIApplicationMain + 1116
22  Rage Masters                      0x000ca004 main (main.m:16)
23  libdyld.dylib                     0x3b630b1c start + 0

 

异常代码是SIGABRT。通常,  SIGABRT 异常是由于某个对象接收到未实现的消息引起的。 或者,用简单的话说,在某个对象上调用了不存在的方法。
这种情况一般不会发生,因为A对象调用了B方法,如果B方法不存在,编译器会报错。但是,如果你是使用selector间接调用方法的,编译器则无法检测对象是否存在该方法了。
回到崩溃日志。它指出闪退发生在编号为0的线程上。 这意味着很可能是在主线程上调用了某个对象没有实现的方法。
如果你接着阅读回溯日志,会发现跟你的代码相关的只有帧22, main.m:16. 这没有多大帮助。 :[
继续向上查看框架调用,出现这个:

 

 

2    CoreFoundation    0x36c02e02 -[NSObject(NSObject) doesNotRecognizeSelector:] + 166

 

这不是你自己写的代码。但至少它确认了是对象调用了一个没有实现的方法。
回到 RMDetailViewController.m文件, 因为那是书签按钮实现动作的地方。 找到书签功能代码:

 

 

-(IBAction)bookmarkButtonPressed {
 
    self.master.isBookmarked = !self.master.isBookmarked;
 
    // Update shared bookmarks
    if (self.master.isBookmarked)
        [[RMBookmarks sharedBookmarks] bookmarkMaster:self.master];
    else
        [[RMBookmarks sharedBookmarks] unbookmarkMaster:self.master];
 
    // Update UI
    [self updateBookmarkImage];
}

 

看起来没什么问题,再检查一下storyboard (XIB文件) ,确认按钮连接的正确性。

就是它了! 在  MainStoryboard.storyboard,按钮连接的是 bookmarkButtonPressed: 而不是bookmarkButtonPressed (注意后面的分号说明方法有一个参数)。 只要将上面的方法签名修改成这样就能修复问题了:

 

 

-(IBAction)bookmarkButtonPressed:(id)sender {
    // Remain unchanged..
}

 

当然,你也可以简单地在XIB文件上删除错误的连接,然后重新连接方法,使XIB文件连接到正确的方法上。两者方法都行。
又处理了一个闪退问题,好样的。:]

场景 3: 表格上的Bug

另一用户抱怨道, “在书签视图上无法删除书签…” 还有另一用户抱怨同样的问题, “当我试图删除书签时,应用闪退…”
这些邮件没什么作用,还是看看崩溃日志!

 

 

Incident Identifier: 5B62D681-D8FE-41FE-8D52-AB7E6D6B2AC7
CrashReporter Key:   5a56599d836c4f867f6eec76afee451bf9ae5f31
Hardware Model:      iPhone4,1
Process:         Rage Masters [20088]
Path:            /var/mobile/Applications/B2121A89-3D1F-4E61-BB18-5511E1DC150F/Rage Masters.app/Rage Masters
Identifier:      Rage Masters
Version:         ??? (???)
Code Type:       ARM (Native)
Parent Process:  launchd [1]
Date/Time:       2012-11-03 13:38:45.762 -0400
OS Version:      iOS 6.0 (10A403)
Report Version:  104
Exception Type:  EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Crashed Thread:  0
Last Exception Backtrace:
0   CoreFoundation                    0x36bff29e __exceptionPreprocess + 158
1   libobjc.A.dylib                   0x34f0f97a objc_exception_throw + 26
2   CoreFoundation                    0x36bff158 +[NSException raise:format:arguments:] + 96
3   Foundation                        0x346812aa -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 86
4   UIKit                             0x37f04b7e -[UITableView(_UITableViewPrivate) _endCellAnimationsWithContext:] + 7690
5   UIKit                             0x3803a4a2 -[UITableView deleteRowsAtIndexPaths:withRowAnimation:] + 22
6   Rage Masters                      0x000fd9ca -[RMBookmarksViewController tableView:commitEditingStyle:forRowAtIndexPath:] (RMBookmarksViewController.m:68)
7   UIKit                             0x3809a5d4 -[UITableView(UITableViewInternal) animateDeletionOfRowWithCell:] + 80
8   UIKit                             0x37fbb0a8 -[UIApplication sendAction:to:from:forEvent:] + 68
9   UIKit                             0x37fbb05a -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 26
10  UIKit                             0x37fbb038 -[UIControl sendAction:to:forEvent:] + 40
11  UIKit                             0x37fba8ee -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 498
12  UIKit                             0x37fbb0a8 -[UIApplication sendAction:to:from:forEvent:] + 68
13  UIKit                             0x37fbb05a -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 26
14  UIKit                             0x37fbb038 -[UIControl sendAction:to:forEvent:] + 40
15  UIKit                             0x37fba8ee -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 498
16  UIKit                             0x37fbade4 -[UIControl touchesEnded:withEvent:] + 484
17  UIKit                             0x37ee35f4 -[UIWindow _sendTouchesForEvent:] + 520
18  UIKit                             0x37ed0804 -[UIApplication sendEvent:] + 376
19  UIKit                             0x37ed011e _UIApplicationHandleEvent + 6150
20  GraphicsServices                  0x3708359e _PurpleEventCallback + 586
21  GraphicsServices                  0x370831ce PurpleEventCallback + 30
22  CoreFoundation                    0x36bd416e __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 30
23  CoreFoundation                    0x36bd4112 __CFRunLoopDoSource1 + 134
24  CoreFoundation                    0x36bd2f94 __CFRunLoopRun + 1380
25  CoreFoundation                    0x36b45eb8 CFRunLoopRunSpecific + 352
26  CoreFoundation                    0x36b45d44 CFRunLoopRunInMode + 100
27  GraphicsServices                  0x370822e6 GSEventRunModal + 70
28  UIKit                             0x37f242fc UIApplicationMain + 1116
29  Rage Masters                      0x000fb004 main (main.m:16)
30  libdyld.dylib                     0x3b630b1c start + 0

 

这看起来跟前面那个崩溃日志很像。是另一个SIGABRT 异常。 你可能想知道是否是相同的问题:发送信息到一个没有实现相应方法的对象?
让我们从回溯日志看看哪些方法被调用了。从底部开始,你的源代码最后被调用的是帧 6:

 

 

6    Rage Masters    0x00088c66 -[RMBookmarksViewController tableView:commitEditingStyle:forRowAtIndexPath:] (RMBookmarksViewController.m:68)

这是UITableViewDataSource 的一个方法. 呵呵?! 毫无疑问苹果已经实现了该方法 —— 你可以重载它, 但不像是还没有实现。而且,这是个可选的委派方法。 所以问题不是调用了一个没有实现的方法。

再看看上面的几个帧:

 

 

3    Foundation    0x346812aa -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 86
4    UIKit         0x37f04b7e -[UITableView(_UITableViewPrivate) _endCellAnimationsWithContext:] + 7690
5    UIKit         0x3803a4a2 -[UITableView deleteRowsAtIndexPaths:withRowAnimation:] + 22

 

帧 5, UITableView调用了它自己的另一个方法  deleteRowsAtIndexPaths:withRowAnimation: 然后是看起来像苹果内部方法的 _endCellAnimationsWithContext: 被调用。然后Foundation framework发生异常 handleFailureInMethod:object:file:lineNumber:description:.
这些分析结合用户的抱怨,看起来是你在处理UITableView删除行过程中有Bug。回到Xcode。你知道看哪里吗 ? 能从崩溃日志中判断出来? 就是 RMBookmarksViewController.m文件的第68行:

 

 

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
 
    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}

 

发现问题了吗? 给你点时间,仔细看一下。
找到了吧! 数据源呢? 代码在表格视图上删除了一行,但并没有修改背后的数据源。把上面的代码替换成下面的就能修复问题了:

 

 

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
 
    RMMaster *masterToDelete = [bookmarks objectAtIndex:indexPath.row];
    [bookmarks removeObject:masterToDelete];
    [[RMBookmarks sharedBookmarks] unbookmarkMaster:masterToDelete];
 
    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}

 

搞定了!走起,讨厌的 bug!!

场景 4: 吃棒棒糖时闪退!

用户邮件说, “当rage master吃棒棒糖时应用就闪退…” 另一用户说, “我让rage master 吃棒棒糖,没几次应用就闪退了!”
崩溃日志如下:

 
 

Incident Identifier: 081E58F5-95A8-404D-947B-5E104B6BC1B1
CrashReporter Key:   5a56599d836c4f867f6eec76afee451bf9ae5f31
Hardware Model:      iPhone4,1
OS Version:          iPhone OS 6.0 (10A403)
Kernel Version:      Darwin Kernel Version 13.0.0: Sun Aug 19 00:28:05 PDT 2012; root:xnu-2107.2.33~4/RELEASE_ARM_S5L8940X
Date:                2012-11-03 13:39:59 -0400
Time since snapshot: 4353 ms
Free pages:        968
Active pages:      7778
Inactive pages:    4005
Throttled pages:   92319
Purgeable pages:   0
Wired pages:       23347
Largest process:   Rage Masters

 

Processes
     Name                    &lt;UUID&gt;                       rpages       recent_max       [reason]          (state)
 
             lsd &lt;6a9f5b5f36b23fc78f87b6d8f1f49a9d&gt;          331              331         [vm]         (daemon) (idle)
            afcd &lt;b0aff2e7952e34a9882fec81a8dcdbb2&gt;          141              141         [vm]         (daemon) (idle)
    itunesstored &lt;4e0cd9f873de3435b4119c48b2d6d13d&gt;         1761             1761         [vm]         (daemon) (idle)
softwareupdatese &lt;2bc4b5ae016431c98d3b34f81027d0ae&gt;          311              311         [vm]         (daemon) (idle)
          Amazon &lt;4600481f07ec3e59a925319b7f67ba14&gt;         2951             2951         [vm]         (suspended)
       accountsd &lt;ac0fce15c1a2350d951efc498d521ac7&gt;          519              519         [vm]         (daemon) (idle)
coresymbolicatio &lt;edba67001f76313b992056c712153b4b&gt;          126              126         [vm]         (daemon) (idle)
           Skype &lt;504cf2fe60cb3cdea8273e74df09836b&gt;         3187             3187         [vm]         (background)
      MobileMail &lt;bff817c61ce33c85a43ea9a6c98c29f5&gt;        14927            14927         [vm]         (continuous)
       MobileSMS &lt;46778de076363d67aeea207464cfc581&gt;         2134             2134         [vm]         (background)
     MobilePhone &lt;3fca241f2a193d0fb8264218d296ea41&gt;         2689             2689         [vm]         (continuous)
      librariand &lt;c9a9be81aa9632f0a913ce79b911f27e&gt;          317              317         [vm]         (daemon)
             kbd &lt;3e7136ddcefc3d77a01499db593466cd&gt;          616              616         [vm]         (daemon)
            tccd &lt;eb5ddcf533663f8d987d67cae6a4c4ea&gt;          224              224         [vm]         (daemon)
    Rage Masters &lt;90b45d6281e934209c5b06cf7dc4d492&gt;        28591            28591         [vm]         (frontmost) (resume)
            ptpd &lt;04a56fce67053c57a7979aeea8e5a7ea&gt;          879              879                      (daemon)
   iaptransportd &lt;f784f30dc09d32078d87b450e8113ef6&gt;          230              230                      (daemon)
       locationd &lt;892cd1c9ffa43c99a82dba197be5f09e&gt;         1641             1641                      (daemon)
         syslogd &lt;cbef142fa0a839f0885afb693fb169c3&gt;          237              237                      (daemon)
    mediaserverd &lt;80657170daca32c9b8f3a6b1faac43a2&gt;         4869             4869                      (daemon)
     dataaccessd &lt;2a3f6a518f3f3646bf35eddd36f25005&gt;         1786             1786                      (daemon)
      aosnotifyd &lt;d4d14f2914c3343796e447cfef3e6542&gt;          549              549                      (daemon)
           wifid &lt;9472b090746237998cdbb9b34f090d0c&gt;          455              455                      (daemon)
     SpringBoard &lt;27372aae101f3bbc87804edc10314af3&gt;        18749            18749                     
      backboardd &lt;5037235f295b33eda98eb5c72c098858&gt;         5801             5801                      (daemon)
  UserEventAgent &lt;6edfd8d8dba23187b05772dcdfc94f90&gt;          601              601                      (daemon)
    mediaremoted &lt;4ff39c50c684302492e396ace813cb25&gt;          293              293                      (daemon)
     pasteboardd &lt;8a4279b78e4a321f84a076a711dc1c51&gt;          176              176                      (daemon)
springboardservi &lt;ff6f64b3a21a39c9a1793321eefa5304&gt;            0                0                      (daemon)
    syslog_relay &lt;45e9844605d737a08368b5215bb54426&gt;            0                0                      (daemon)
      DTMobileIS &lt;23303ca402aa3705870b01a9047854ea&gt;            0                0                      (daemon)
notification_pro &lt;845b7beebc8538ca9ceef731031983b7&gt;          169              169                      (daemon)
    syslog_relay &lt;45e9844605d737a08368b5215bb54426&gt;            0                0                      (daemon)
             ubd &lt;74dc476d1785300e9fcda555fcb8d774&gt;          976              976                      (daemon)
        twitterd &lt;4b4946378a9c397d8250965d17055b8e&gt;          730              730                      (daemon)
         configd &lt;4245d73a9e96360399452cf6b8671844&gt;          809              809                      (daemon)
   absinthed.N94 &lt;7f4164c844fa340caa940b863c901aa9&gt;           99               99                      (daemon)
filecoordination &lt;fbab576f37a63b56a1039153fc1aa7d8&gt;          226              226                      (daemon)
       distnoted &lt;a89af76ec8633ac2bbe99bc2b7964bb0&gt;          137              137                      (daemon)
            apsd &lt;94d8051dd5f5362f82d775bc279ae608&gt;          373              373                      (daemon)
        networkd &lt;0032f46009f53a6c80973fe153d1a588&gt;          219              219                      (daemon)
      aggregated &lt;8c3c991dc4153bc38aee1e841864d088&gt;          112              112                      (daemon)
        BTServer &lt;c92fbd7488e63be99ec9dbd05824f5e5&gt;          522              522                      (daemon)
   fairplayd.N94 &lt;7bd896bd00783a48906090d05cf1c86a&gt;          210              210                      (daemon)
       fseventsd &lt;996cc4ca03793184aea8d781b55bce08&gt;          384              384                      (daemon)
         imagent &lt;1e68080947be352590ce96b7a1d07b2f&gt;          586              586                      (daemon)
   mDNSResponder &lt;3e557693f3073697a58da6d27a827d97&gt;          295              295                      (daemon)
       lockdownd &lt;ba1358c7a8003f1b91af7d5f58dd5bbe&gt;          389              389                      (daemon)
          powerd &lt;2d2ffed5e69638aeba1b92ef124ed861&gt;          174              174                      (daemon)
      CommCenter &lt;1f425e1e897d32e8864fdd8eeaa803a8&gt;         2212             2212                      (daemon)
         notifyd &lt;51c0e03da8a93ac8a595442fcaac531f&gt;          211              211                      (daemon)
     ReportCrash &lt;8c32f231b2ed360bb151b2563bcaa363&gt;          337              337                      (daemon)

 

这日志跟我们前面见到的相差很多。

这个一个来自iOS 6的低内存崩溃日志。正如我们前面所说的,低内存崩溃日志与其他类型的崩溃日志很不一样,它们不指向特定的文件和代码行。相反,它们画出了闪退时设备上的内存使用情况的图表。

至少,头部还是跟其他崩溃日志很像的:  提供了 Incident Identifier, CrashReporter Key, Hardware Model, OS Version等信息。

接下来部分是低内存崩溃日志特有的:

  • Free pages 指可用内存页数。每页大小约是4KB, 上面的日志中,可用内存约为3,872 KB (或者说 3.9 MB)。
  • Purgeable pages 是那部分可被清除或重用的内存。在上面的日志中,是0KB。
  • Largest process是闪退时使用大部分内存的应用名称,在上面的日志中,正是你的应用!
  • Processes显示了闪退时各进程列表,还包含内存使用量。包含进程名 (第一列), 进程唯一标识符(第二名), 进程使用的内存页数(第三列)。最后一列是每个应用的状态。通常,发生闪退的应用的状态是 frontmost。 这里是 Rage Masters, 使用28591 页 (or 114.364 MB) 内存——这内存太多了!

通过,最大进程和frontmost状态的应用是相同的, 而且也是引起低内存闪退的应用进程。但是也可能看到最大进程和 frontmost状态应用不同的例子。比如,如果最大进程是SpringBoard, 忽略它 , 因为 SpringBoard 进程是显示主屏幕的应用,出现在你双击home按钮等情况,而且它是一直活动的。
低内存发生时,iOS向活动的应用发出低内存警告并终止后台应用。如果前台应用仍然继续增长内存,iOS将终止它。
为了查找低内存问题的原因,你必需使用Instruments剖析应用。如果你不知道怎么做,可以看一下我们 一篇关于这个方面的教程.。 :] 另外, 你也可以走捷径,响应低内存警告通知,以解决部分闪退问题。
回到Xcode查看RMLollipopLicker.m文件。 这是实现吃棒棒糖的视图控制器。看看源代码:

 

 

#import "RMLollipopLicker.h"

#define COUNT 20

@interface RMLollipopLicker ()
@property (weak, nonatomic) IBOutlet UIProgressView *progressView;
@property (weak, nonatomic) IBOutlet UILabel *label;
@property (weak, nonatomic) IBOutlet UILabel *lickedTimeLabel;
@end

@implementation RMLollipopLicker {
    NSOperationQueue *queue;
    NSMutableArray *lollipops;
}

#pragma mark - Life cycle

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.progressView.progress = 0.0;
    self.label.text = [NSString stringWithFormat:@"Tap on run and I'll lick a lollipop %d times!", COUNT];
    self.lickedTimeLabel.text = @"";
    
    lollipops = [[NSMutableArray alloc] init];
    queue = [[NSOperationQueue alloc] init];
}

- (void)lickLollipop {
    NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"Lollipop" withExtension:@"plist"];
    NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfURL:fileURL];
    NSString *lollipop = [dictionary objectForKey:@"Lollipop"];
    [lollipops addObject:lollipop];
}

#pragma mark - IBActions

- (IBAction)doneButtonPressed:(id)sender {
    
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (IBAction)runButtonPressed:(id)sender {
    
    [sender setEnabled:NO];
    [queue addOperationWithBlock:^{
        
        for (NSInteger i = 0 ; i = COUNT) {
            self.label.text = [NSString stringWithFormat:@"Tap on run and I'll lick a lollipop %d times!", COUNT];
            self.progressView.progress = 0.0;
            [sender setEnabled:YES];
        }
    }];
}
}];

}

@end

 

当用户点击运行按钮, 应用开始一个背景线程,调用 lickLollipop 方法若干次,然后更新界面反映吃棒棒糖的数量。 lickLollipop 方法从属性列表文件(PLIST)文件读取一个长字符串,然后添加到数组上。这些数据并不重要, 能在不影响用户体验的前提下重新创建。
利用每种能够清除和重建数据而不影响用户体验的情况是好习惯。这样能够方便地释放内存,减少低内存警告。
那么,如何提高代码质量呢? 实现 didReceiveMemoryWarning 方法,像下面这样处理数据:

 

 

-(void)didReceiveMemoryWarning {
    [lollipops removeAllObjects];
    [super didReceiveMemoryWarning];
}

 

搞定!

下一步?

万岁,你研究了4个闪退案例! 你的应用更完善了,并且学到了一些重要的调试技巧。
你可以到 这里下载改进后的项目代码。
你喜欢iOS崩溃日志揭秘吗? 希望你能将学到的运用到你自己的应用中,也希望你能处理闪退,使你的应用更强壮!



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



Viewing all 15843 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>