何处安放我们的 Go 代码

用了近半年的 Go,真是有种相见恨晚的感觉。简洁的语法、完善并强大的开发工具链,省去新手不少折腾的时间,可以专注写代码。
这期间也掌握了不少技巧与惯用法(idioms),比如 prosumer,就是一个踩了 chan/timer 一些坑后实现生产者/消费者模式框架。但今天不去谈 chan 的使用方式,而是来谈一个最基本的问题,Go 代码应该放在哪里,其实也就是 Go 的包管理机制,有时也称为版本化,其实是一个意思。这看似简单,却让不少 Gopher 吃了不少苦头

阅读全文

写给新手的 Go 开发指南

转眼加入蚂蚁已经三个多月,这期间主要维护一 Go 写的服务器。虽然用的时间不算长,但还是积累了一些心得体会,这里总结归纳一下,供想尝试 Go 的同学参考。
本文会依次介绍 Go 的设计理念、开发环境、语言特性。本文在谈及语言特性的时也会讨论一些 Go 的不足之处,旨在给读者提供一个全面的视角。

阅读全文

Clojure 开发经验总结

大概在两年半前,我开始陆陆续续写了一系列文章,来介绍如何上手、深入 Clojure,后来有幸加入 LeanCloud 写了两年的 Clojure,期间制作了一套七集的教学视频,算是对这门语言有了较为全面的认识。
鉴于国内 Clojure 普及程度很低,我觉得有必要把这些年的经验整理出来,可能会有些片面,但贵在真实,希望我的这些实战经验能帮助到后面 Clojure 的学习者。

阅读全文

Java 垃圾回收权威指北

毫无疑问,GC(垃圾回收) 已经是现代编程语言标配,为了研究这个方向之前曾经写过四篇《深入浅出垃圾回收》博文来介绍其理论,之后也看了不少网络上关于 JDK GC 原理、优化的文章,质量参差不齐,其中理解有误的文字以讹传讹,遍布各地,更是把初学者弄的晕头转向。
不仅仅是个人开发者的文章,一些大厂的官博也有错误。
本文在实验+阅读 openjdk 源码的基础上,整理出一份相对来说比较靠谱的资料,供大家参考。

阅读全文

Java 线程同步原理探析

现如今,服务器性能日益增长,并发(concurrency)编程已经“深入人心”,但由于冯诺依式计算机“指令存储,顺序执行”的特性,使得编写跨越时间维度的并发程序异常困难,所以现代编程语言都对并发编程提供了一定程度的支持,像 Golang 里面的 Goroutines、Clojure 里面的 STM(Software Transactional Memory)、Erlang 里面的 Actor

阅读全文

形单影只的 Socket

最近工作上遇到过几次因 http client 没有配置超时相关参数,导致线程数占满或应用卡住的情况,出问题时线程的堆栈大致是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
"qtp325266363-35729" #35729 prio=5 os_prio=0 tid=0x00007f5154033000 nid=0x1cf8f runnable [0x00007f4f7f511000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
at sun.security.ssl.InputRecord.read(InputRecord.java:503)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:983)
- locked <0x00000006e1494d68> (a java.lang.Object)
at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:940)
at sun.security.ssl.AppInputStream.read(AppInputStream.java:105)
- locked <0x00000006e1496d88> (a sun.security.ssl.AppInputStream)
at org.apache.http.impl.conn.LoggingInputStream.read(LoggingInputStream.java:84)
at org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:137)
at org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:153)
at org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:282)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:138)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163)

阅读全文

深入浅出垃圾回收(四)分代式 GC

上文介绍的增量式 GC 是对 mark 阶段的一大优化,可以极大避免 STW 的影响。本文将要介绍的分代式 GC 根据对象生命周期(后面称为 age)的特点来优化 GC,降低其性能消耗。

阅读本文需要熟悉之前提及的术语

阅读全文

深入浅出垃圾回收(三)增量式 GC

上一篇文章中介绍的 MS 优化策略都是围绕 sweep 阶段展开,但 mark 阶段会导致应用程序挂起,也就是常说的:stop-the-world(STW),这严重影响了 Tracing GC 的应用场景。本文即将介绍的增量式 GC 可以大大缓解 STW 问题。

阅读全文

深入浅出垃圾回收(二)Mark-Sweep 详析及其优化

在上一篇文中介绍的追踪类(tracing)GC 较引用计数(Reference Counting)性能更高,但原生的追踪类 GC 也有其自身缺点,需要对其进行改造才能真正的名副其实。这篇文章就来介绍与之相关的内容。

阅读全文

深入浅出垃圾回收(一)简介篇

GC 算法作为计算机科学领域非常热的研究话题之一,最早可追溯到 1959 年1,由 John McCarthy 在 Lisp 中实现来简化内存管理。早期的 Lisp 之所以被大众诟病慢,主要原因就是当时的 GC 实现相对简单,对程序的影响(overhead)比较严重。经过几十年的发展,GC 算法已经很成熟了,可以完全摆脱「速度慢」这个让人望而却步的标签。

阅读全文