性能优化 && U3D开发






乡亲们, AFN 使用姿势不当引起的 Retain Cycle @ 青浦区 iOS 中学



知道存在,内存漏的飞快,用户日活成百上千的情况。

memory footprint 不佳,似乎也没什么。

程序一般也不会变慢。

内存问题,程序崩的,遇见的也挺少。




















写在最后

老王猜想,对于一般的团队,
系统内存当然是,想怎么用怎么用,不用花钱的。
技术小组长,技术负责人,产品负责人,谁管这个呀,

产品负责人关心的是产品体验 (崩溃率 bugly , 还有性能( 卡顿,界面卡不卡 , 接入听云, 啥啥啥))、 产品运营 (PV / UV)

老王猜想,必须写在最后,否则就没人看了












修改源码,讲个故事,YYModel 做梦都要哔哔




先读一下语义


YYModel 非常优秀,本文没发现有改进的地方,

改动一下,贴近所做的项目。


怎么说,网上博客那么多
讲个故事
很敬仰上海的一位叫王大宇的 iOS 工程师,

做梦开始








醒来啦


















僵尸对象

等内存错误














本文小结下,内存管理的语义:

需要该对象的时候,他就得在。不需要他的时候,他最好被释放了。
合理的利用资源。

需要该对象的时候,他不在,释放早了。
给他发消息,程序会崩,EXC_BAD_INSTRUCTION

不需要该对象的时候,他还在。内存可能泄漏了。一般是存在循环引用 ( retain cycle )


iOS 的内存分析,工具挺多

可以使用 Xcode 的 Debug 工具,内存图( 点一下就好,断点旁边 )

0

这么用,
在重点测试的界面,多操作,然后退出。
重复几次。确认系统缓存已初始化。
退出重点测的界面后,开内存图,
如果内存释放的干净,就没什么 retain cycle 等内存泄漏。

内存图自带断点效果,会暂停 app 的运行
可以看到此刻存在的所有对象。

环节短的循环引用,明显可见,找起来很快。

通过内存图,左边列表中,可以看到当前的所有对象,以及它们的数量。

最关心的就是感叹号,代表异常, 就是内存泄漏, 可能 Retain Cycle

0

本文 Demo ,可见系统的代理 AppDelegate 实例, 相关 ViewController . 可看到图片视图有 24个。

中间大片的区域是对象的内存图,他们是怎么关联的。可以参考下

左边栏的右下方按钮,可以直接筛选出内存有错误的对象,方便找出内存泄漏的对象

1

可看出本文 Demo 内存泄漏严重。左边栏,点开几个带感叹号的,看情况。 右边栏,有一些具体信息

11

photo 照片模型对象,持有一个 location 位置的模型对象,
location 位置的模型对象,持有一个对象,
那对象,又持有 photo 照片模型对象。

三个对象,构成了一个引用的圈, retain cycle


发现问题了,解决就是改代码
很熟悉,直接改。
可以全局搜关键字,本文 demo 搜 .location
可以根据右边栏的信息找,


0

知道是哪个类,又有一个 closure 对象

0

可找到错误代码


        photoModel.location?.reverseGeocodedLocation(completion: {   (locationModel) in
            self.photoLocationLabel.attributedText = photoModel.locationAttributedString(withFontSize: 14.0)
           
        })
    }

photoModel 有一个 location 的属性,location 持有一个匿名函数 closure.
这个 closure 又引用了 photoModel。

不知道这个 closure 有没有 retain 该 photoModel,
点进方法看,
这是一个逃逸闭包,赋给了 LocationModel 的 placeMarkCallback 属性,强引用

func reverseGeocodedLocation(completion: @escaping ((LocationModel) -> Void)) {
        if placemark != nil {
            completion(self)
        }
        else {
            // 查看 completion
            placeMarkCallback = completion
            if !placeMarkFetchInProgress {
                beginReverseGeocodingLocationFromCoordinates()
            }
        }
    }

与 Xcode 内存图检查到的一致。


解决循环引用,就是加 weak

ARC , 自动引用记数, iOS 用来管理内存的。
循环引用,retain cycle, 是 ARC 搞不定的地方

一个对象的引用记数, 就是有多少个其他的对象,持有对他的引用。( 就是有多少个其他的对象,有指针指向他)

当这个对象的引用计数为 0, iOS 的 ARC 内存机制知道这个对象不必存在了,会找一个合适的时机释放。

循环引用,多个对象相互引用,形成了一个圈( 引用的链路 )。
循环引用,问题很严重,内存泄漏了
( 打个比方: 你找 iOS 系统借了钱,少还一大截。人家系统没说什么, 心里都记着 )

加 weak, ARC 就明白了,
( 因为 weak 是弱引用,不会增加该对象的引用记数。
直接写,隐含了一个 strong 的语义,默认 retain , 该对象的引用记数 + 1 )

链路就断了,内存回收成功。


Swift 的 closure 中,可以添加一个弱引用列表。
这个捕获列表可以让指定的属性弱引用。
closure 使用弱引用,就好


func reverseGeocode(locationForPhoto photoModel: PhotoModel) {
        photoModel.location?.reverseGeocodedLocation(completion: {  [ weak photoModel] (locationModel) in
            self.photoLocationLabel.attributedText = photoModel?.locationAttributedString(withFontSize: 14.0)
           
        })
    }


Xcode 的调试计量工具很强大,调试内存的时候,可切换调试视图层级等

1

左边栏的右上方的按钮,可以切换调试的选项,
内存转 UI, 内存转线程

2


通过使用 Xcode 内存图,内存泄漏少了很多。
重复操作三五次,又发现一个内存泄漏

0

对象结点很多,看图挺复杂的

可以用 Instruments 的 Leaks

0

Leaks 自带两个模版 Allocation 和 Leaks,

Allocation 模版对 app 运行过程中分配的所有对象的内存,都追踪到了。
上方的时间线展示了,已经分配了多少兆的内存。

All Heap & Anonymous VM, 所有堆上的内存,和虚拟内存 ( WWDC 2018/416 , 讲的比较详细)

下方的标记按钮,可以做分代标记

0

Leaks 模版会检查 app 所有的内存,找出泄漏的对象 ( 释放不了的对象 )

Instruments 的内存检查机制是,默认每隔 10 秒钟,自发的取一个内存快照分析

0



反复操作,找到第一个 Leaks, 可以暂停下

0

下方的 Leaks 详情表中,头部的 Leaks 按钮,有三个选项,
默认选项就是第一个, Leaks,
展示了所有内存泄漏的对象。

0

下方的右边栏就是更多信息,展示了详情界面每一列对象的进一步的资料

Leaks 详情表中,每一列对象,有一个灰色的箭头按钮,

0

点进去,可以看引用计数的增减日志

0

一般先看看第二个 Cycles & Roots, 又是一张内存图

photoModel 是循环圈的根结点,与左边的对象结点列表一致

1

有用的是第三个选项 Call Tree , 调用树

与 Time Profiler 的 Call Tree 不一样,
Time Profiler 的 Call Tree 采集的是应用中所有的方法调用,
Leaks 的 Call Tree 采集的是分配内存与内存泄漏相关的方法调用。

Call Tree 的选项一般勾选 Hide System Libraries 和 Separate by Thread.
Hide System Libraries , 隐藏系统的方法。系统的方法改不了,是黑盒,参考意义有限。
Separate by Thread. 将方法堆栈,按线程分开。一般出问题多在主线程,优先看 main thread.

0

按住 Alt 键,点击方法名称左边的小三角,可以展开调用栈。

1

又看到了这个方法 func reverseGeocode(locationForPhoto photoModel: PhotoModel)

再检查下

func reverseGeocode(locationForPhoto photoModel: PhotoModel) {
        photoModel.location?.reverseGeocodedLocation(completion: {  [ weak photoModel] (locationModel) in
            self.photoLocationLabel.attributedText = photoModel?.locationAttributedString(withFontSize: 14.0)
           
        })
    }

self 是一个 CatPhotoTableViewCell 实例,self 持有 photoModel 属性,
( 函数里面的 photoModel, 使用的是 func updateCell(with photo: PhotoModel?) { 方法中传入的 self 的 photoModel 属性)
photoModel 持有 location 属性, location 属性持有一个逃逸闭包,
该逃逸闭包持有 self.

之前用 weak 处理了三对象的循环引用,现在有一个四对象的循环引用。

四对象的循环引用中 photoModel 在之前的处理中,已经弱引用了。本来好像没什么问题的。

估计系统没及时释放的 weak 的 photoModel,又泄漏了。

本文中,采用 Xcode 内存图,难以复现。有时候有。


解决就是再加一个 weak.


检查项目中的循环引用,通常使用分代式分析 ( Generational Analysis )

先记录一个内存使用的基线 A ( 当前使用场景, 建议用重点测的场景前的那一个 ),
进入一个场景 ( Controller 重点测的场景), 打个标 ( 记录现在的内存使用情况 ) B ,
再退出该场景,再打一个标 C。

如果 A < B , A = C , 正常,内存回收的不错。
如果 A < B <= C , 异常,内存很可能泄漏了

换句话,套路很简单,设立内存基线,点击进入新界面,(操作一下,滚一滚)
然后弹出,内存往往会先升后降。

这种操作,需要重复几次。找出必然。确认系统缓存已初始化,在运行。
( 有点类似苹果的单元测试算函数执行时间,跑一遍,就是运行了好几次的函数,取的平均值。 )


这里有一个很经典的面试题:

app 发布前,一般会系统检查循环引用,内存泄漏,怎么处理呢?

( 换个说法, 怎么分析 app 堆的快照? )


相关代码: https://github.com/BoxDengJZ/Instruments_Wen

更多资料: 视频教程,practical-instruments


同质博客: Memory

扩展阅读:

命令行工具 vmmap - 查看虚拟内存 : WWDC 2018:iOS 内存深入研究



























hr>











hr>











hr>







hr>


















hr>














hr>












hr>












hr>












iOS 电量消耗改善:一招套路及相关姿势

工作流

解决电量问题的工作流:

先使用 Xcode Energy Gauge 分析出哪一块耗电(网络和 motion , 还是定位 ), 用 Time Profiler 定位问题与解决 ( Instruments ), 得到用户好的反馈。

三个原则:
  • Do it never/do it less (能不做,就不做。少做的,好)
    比如: 网络请求,先压缩数据

  • Do it at a better time (合适的时机处理 )
    网络请求,使用缓存机制,设置内容验证( 需要的数据是否更新了 ),或者缓存的失效时间

  • Do it efficiently ( 有效处理 )
    合并网络请求。一次请求大量数据,比多次请求少量数据省电


套路很简单,将手机放在桌子上,Xcode 里面启动 app, 并检测,啥也不干。如果电量消耗较高,很不合适了

本文解决的两个问题,给 CoreMotion 更新设置过滤,干掉频繁的日志上传


WWDC 推荐使用 Xcode Debug 栏的 Energy Debug Gauge。( 调性能,都是用真机。机器老一点,效果更好 )
Energy Debug Gauge 形象、直观

Energy Debug Gauge

可看出,当前手机的耗电情况,耗电低、高、很高。苹果的三个阶段,有些不太细致。(左上的 Utilization, Current Impact)

app 的平均能耗,一目了然 ( 右上的 Average ) 。

每一个时刻,耗电的是什么。 CPU 、网络、文件 I/O 、定位,哪些消耗了。( 中间的 Energy Impact )



Xcode Energy Gauge 可以快速定位问题,想要进一步的细致分析,下面有各种选项,跳转到对应的 Instrumens 模版。

比如:

分析 CPU 使用的 time profile, (能够知道代码的执行情况了,根据函数的调用消耗。找出权重大的,干掉不必要的。)

分析网络活动的 network profile, 分析定位活动的 location profile


本文 Demo

before

这里电量消耗很高,很稳定

主要是 CPU 和网络请求在耗电。


使用 Instruments 的 Time Profiler 分析,

CPU 分析

可以先放大上面的 time line,再选择一个时间段,在调用树 call tree 中,进一步分析。
Time Profiler 的选项默认是按线程划分的,再选一个隐藏系统的。(系统的,可以参考一下,到底发生了什么。系统的改不了。可以改自己的源代码 )

option

在调用树的表格中,按权重展开 ( weight ),要干掉的就是权重大的,耗时间的。

接着展开主线程 ( main thread 。看上图,其他线程的耗时,相比主线程的,可忽略 ),
按住 Option 键,点击 main thread 左边的小三角,可以一下子展开很多。

可清晰看出,耗时严重的是 450 毫秒左右的那一行 thunk for ... CMDeviceMotion? ...

里面调用了一个耗时的方法,CatPhotoTableViewCell.panImage , 上图, 454 毫秒中,占 419 毫秒。

hop

点击进入详情,就看到代码了。

在 CatFeedViewController 的 viewDidLoad 方法中,有一个倾斜的设置

motionManager.startDeviceMotionUpdates(to: .main, withHandler:{ deviceMotion, error in
            guard let deviceMotion = deviceMotion else { return }
            let xRotationRate = CGFloat(deviceMotion.rotationRate.x)
            let yRotationRate = CGFloat(deviceMotion.rotationRate.y)
            let zRotationRate = CGFloat(deviceMotion.rotationRate.z)
            //  y > z, 这个动作是翘起来
            //  y > x + z, 这个动作是斜着翘起来
              if abs(yRotationRate) > (abs(xRotationRate) + abs(zRotationRate)) {
                for cell in self.tableView.visibleCells as! [CatPhotoTableViewCell] {
                    cell.panImage(with: yRotationRate)
                }
              }
  })

现在的代码显示栏 ( 原来的 Call Tree 表格 ), 右上角有一个 Xcode 的小图标,点击返回 Xcode 调试代码。

手机没动,老是调用 cell.panImage(with: yRotationRate), 根本就没效果。

设置一下,调用 cell.panImage 的最小手机幅度比较好。幅度小,根本就,没效果。
添加一个属性记录,过滤掉手机小的抖动。

private var lastY = 0.0
override func viewDidLoad() {
        super.viewDidLoad()
        ......
        motionManager.startDeviceMotionUpdates(to: .main, withHandler:{ deviceMotion, error in
            guard let deviceMotion = deviceMotion else { return }
          
            // 添加了这两行
           guard abs(self.lastY - deviceMotion.rotationRate.y) > 0.1 else { return }
            self.lastY = deviceMotion.rotationRate.y

            let xRotationRate = CGFloat(deviceMotion.rotationRate.x)
            let yRotationRate = CGFloat(deviceMotion.rotationRate.y)
            let zRotationRate = CGFloat(deviceMotion.rotationRate.z)
              if abs(yRotationRate) > (abs(xRotationRate) + abs(zRotationRate)) {
                for cell in self.tableView.visibleCells as! [CatPhotoTableViewCell] {
                    cell.panImage(with: yRotationRate)
                }
              }
        })
    }


还有一个使用 Timer 定时发送日志的问题,CPU 根本没有空闲的时间,开销很大。

具体见文末的 Demo Code.

最后这样

after

会慢慢降下去,至于电量低消耗。
需要大约两分钟时间,一屏幕放不下。


Instruments 的 Energy Log 有问题,连着 Xcode 调试的部分 gg 了

Instruments 的 Energy Log 模版用途不大

因为不能手机在线调试。Energy 是空的, 或者提示 No Data,

这是苹果的一个知名 bug .(参见 Apple Forum )

Energy Log 模版的模块挺丰富的,可以看屏幕亮度、定位、蓝牙、GPU 和网络等等的功耗情况,其中网络又包括 WiFi 和蜂窝网络。


想着一边给手机充电,一边调试电量损失,不靠谱。

试了下,无线用 Instruments 的 Energy Log 模版调试,结果一样。

连着 Xcode 调试耗电,也没有数据。

无线用 Instruments 调试,首先要设置 Xcode 无线 Debug ,

无线 debug 功能,隐藏在 Xcode 的 Window > Devices and Simulators 中。

Devices_and_Simulators

实际上是,使用共享的无线网络,取代了数据线的连接,连上了。会有一个网络的 Icon . 上面还有提示语 ( connected , 连上了 )

如下图:

connect

更多参见博客 How to use Wireless Debugging on Xcode 9

然后就可以设置 Instruments 无线设备调试了,

更多参见苹果文档 Energy Efficiency Guide for iOS Apps



instruments 的 Energy 模版,将电量消耗的程度划分为 20 个级别。
0 代表不耗电,自然 app 没做什么
20 代表耗电严重
现在要看到,只能导入离线的 log。

在手机的设置中,开发者选项中的 Logging, 选中 Energy, 点击开始录制:

开发者

之后,使用你的 app 一段时间,(可以重点测耗电功能)
开发者选项中的 Logging, 点击完成录制,
导入电量消耗 log 数据,到 Instruments 的 Energy Log 模版.

导入

老版本的不行( 11.4 ), 没数据。操作的时候,手机的设置 app ,还老是闪退。

手机升级到最新版(12.1 , 20181127),试了多次,也不行, 本文觉得是彻底挂了

(本文中,重启手机,升级手机。没有重启电脑。也有可能是,我的手机和电脑坏了)


湿一点,好消化

耗电是不好的。

写入硬盘与网络请求,都是高耗电操作。

网络请求特别耗电,每一个网络请求,手机设备需要使用他的蜂窝网络天线,发送无线电波。

网络的质量与类型,对于耗电的影响也很大。
使用 Wi-Fi 比 3G , 4G 要省电得多。 使用 4G 比 3G 要省电,因为 4G 的信号更强。

计时器,能不用就不用。( NSTimer )

一般情况下,app 都用 Timer 做了很多无用功。
比如, 一个列表屏幕, 上方 banner 计时器,往下滑到看不见 banner ,就可以暂停计时器。上滑,看得见 banner 了,又可以恢复。同样的,进入子界面,又可以暂停,或者释放,...

例子: 定时做重复的大量工作不好,可能每当系统休眠(系统要降低能级了),系统又被唤醒了,开始功耗。

定位

与网络请求类似,手机设备定位通过 GPS 天线发送信号,也挺耗电的。
如果 app 经常去获取手机设备的精确定位,定位精度越高,能耗越严重。
建议使用策略,手机的负担会小很多。
( 🌰,Deferred location updates, 位置更新延迟(直到移动了 x 米或者时间超过了 xx 秒 )、
significant location change, 定位变化比较大的时候,唤醒、
region monitoring, 监测用户进入或离开特定地理区域)

Motion 物理引擎,动态效果更新状态,挺耗电的。

使用罗盘、陀螺仪、加速计,都消耗不小。


相关代码: https://github.com/BoxDengJZ/Instruments_Wen

更多资料:

WWDC 2015 Debugging Energy Issues

视频教程,practical-instruments


本文 Demo 使用的是 500 px 的 API .



后来发现有人都写过了

好尴尬

想了一下,可以写他没交代的。苹果更新太快,人是物非









本文例子,有些单薄。
苹果的有一期将性能优化的 WWDC ,好像例子感觉也不怎么样。( 还记得,那讲师像是咱村里的 )



手机性能优化的重点,就是界面渲染。一般,计算任务都交给服务端。

界面渲染慢,就不好了。


常见问题,就是离屏渲染。 这里用 NSShadow 处理掉 CALayer 的阴影属性带来的离屏渲染。

常见的离屏渲染代码:
绘制阴影,

        var label = UILabel()
        label.layer.shadowColor = UIColor.lightGray.cgColor
        label.layer.shadowOffset = CGSize(width: 0.0, height: 5.0)
        label.layer.shadowOpacity = 1.0
        label.layer.shadowRadius = 5.0
        
        label.text = "离屏渲染"

写完以后,CPU 和 GPU 都没有充足的信息绘制阴影效果。
过程是, CPU 会先把文本传出去,请求 GPU (CPU 把文本传给 GPU ),创建一个内存中的位图上下文(GPU 把文本放进去 ),离屏渲染这就开始了。
这个上下文缺信息,不在屏幕上, 不是帧缓冲。(渲染出来的图形上下文,不属于当前帧)。

之前 CPU 把文本处理好了,现在 CPU 处理文本效果(这里是阴影)。

然后,CPU 拿到渲染好的文字,基于渲染出来的每一个像素的透明度,计算出阴影的形状。
最后,CPU 把最新计算出来的文字阴影形状的信息,传给 GPU .
GPU 有阴影信息,有之前图形上下文的渲染文本,GPU 就渲染好了最终的文字及其阴影,交给帧缓冲 (Frame Buffer), 我们就看到了。

这段代码要渲染两次,出现了离屏渲染。对 GPU 的性能有影响。他需要等待 CPU 来算出阴影的形状。

因为我们要 60 的帧数 ( FPS ), GPU 准备帧缓冲,渲染出当前帧,只有 17 微秒。拖累了主线程,屏幕刷新不过来。


对于图形阴影, 用 layer 的 shadowPath. 对于文字阴影,用 NSShadow .

layer 的四个属性 shadowColor , shadowOffset ,shadowOpacity ,shadowRadius ,一般性能不好。

对于一个视图框, 通过 layer 在周边加阴影。用 layer 的 shadowPath,创建一个 UIBezierPath,

UIBezierPath(rect: CGRect(x: 0, y: 0, width: 50, height: 50))
// size of your label

与之前不同,图层不用渲染两次。现在 GPU 有了足够的信息绘制阴影效果, 就不用离屏渲染了。

对于文字阴影,用 NSShadow ,用 path 就比较难。


UI 性能优化主要用的是 Instruments 的 Core Animation 模版。

过去,Core Animation 模版几个调试选项非常强大,正常的绿色, 异常的红色,离屏渲染的黄色。
(光栅化有效,光栅化后缓存的内容成功复用。界面会显示绿色。
光栅化失效的部分,呈红色。光栅化后缓存的内容没有复用,光栅化隐式创建的位图浪费了。直接重新绘制。 )

现在这些利器都在 Xcode 里了,可以直接使用。

真机运行直接选择,

直接 debug

本文 Demo 使用的是 500 px 的 API .

调试界面的离屏渲染,用的是 Color Offscreen-Rendered Yellow 选项。

调试目标是,出现大片的绿色。

离屏渲染

这里可以用 Apple 的 UIKit 框架下的 NSShadow 对象。

            let shadow = NSShadow()
            shadow.shadowColor = UIColor.lightGray
            shadow.shadowOffset = CGSize(width: 0.0, height: 5.0)
            if let mutableAttributedString = label.attributedText as? NSMutableAttributedString{
                let range = NSRange(location: 0, length: mutableAttributedString.string.count)
                mutableAttributedString.addAttribute(NSAttributedString.Key.shadow, value: shadow, range: range)
            }

解决离屏渲染
用背景色处理掉混色。

界面图层混色,就是多个视图的位置有重叠,他们又不是透明的。重叠区域的每一个像素,GPU 需要算出一种新的颜色(混色)。
如果这种效果,不是 UI 设计的,尽量避免。

调试界面的图层混色,用的是 Color Blended Layer 选项。

UILabel 建议设置背景色。UILabel 有文字,那就不透明,Label 默认的背景色是透明色,与父视图的背景色,混杂了。GPU 对相关位置的颜色,需要重新计算。

指定 Lable 背景色前
  
override func awakeFromNib() {
        super.awakeFromNib()
        [userNameLabel, photosLikeLabel, photosDescriptionLabel, photoTimeIntevalSincePostLabel].forEach {
            $0?.backgroundColor = UIColor.white
        }
}

设置后, 效果明显

指定 Lable 背景色后

混色,如果不是 UI 指定的效果,建议处理掉。

界面图层混色,常见的影响因素是 view 的 alpha 属性。 alpha 小于 1, 一般自带混色效果。
其他知识点介绍: 卡顿(丢帧)。

Instruments 的 Core Animation 模版的时间线,就是 FPS. 显示随着时间,app 的帧率波动。

Instruments 的 Core Animation

可以方便的读取帧数,直观的了解那些界面要改善。

用代码检测卡顿,自然是 CADisplayLink ,网上相关博客很多。







































我之前是在小公司,每天的工作内容就是和策划美术老板撕逼,催策划案子,催美术资源, 然后照着那个永远在改的案子边做边改,反过来被策划和老板催实现,改bug。做完以后老板大手一挥,这个功能去掉,这个功能要改,嗯嗯。。。还要和服务器讨论接口设计。有时候对美术给的资源不满意还会自己PS或者开3DMAX弄一下。。。反正是真正写代码的时候少,需要的功能都直接网上找,每天都很忙又不知道在忙些什么。

我想了解一下iOS开发的工作内容大概是怎样呢?
也会和产品、UI撕逼吗?
是写代码的时候多,还是处理资源的时候多?
对于UI实现是鼠标拖拖拖吗,是程序来做还是设计来做?
开发过程中案子改动频繁吗?
周围有话语权的人多吗,是不是老板产品设计谁都可以对你指手画脚?
创业小公司和大公司有何不同吗?
对数据(比如游戏的次日留存,流水这些)迷信或者说崇拜吗? 公司会对同行各种鄙视,对自己数据各种吹逼吗?
老板爱画大饼的多么?
像游戏行业梦想一夜暴富的多么?
加班多么,加班的原因多是什么?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容