tl; dr:我如何做类似下面的编写代码:
def notFunctor[M[_] : Not[Functor]](m: M[_]) = s"$m is not a functor"
Run Code Online (Sandbox Code Playgroud)
' Not[Functor]',是这里的组成部分.
当'm'提供的不是Functor时,我希望它成功,否则编译器会失败.
解决:跳过问题的其余部分,然后直接回答下面的答案.
我粗略地说,我想要完成的是"负面证据".
伪代码看起来像这样:
// type class for obtaining serialization size in bytes.
trait SizeOf[A] { def sizeOf(a: A): Long }
// type class specialized for types whose size may vary between instances
trait VarSizeOf[A] extends SizeOf[A]
// type class specialized for types whose elements share the same size (e.g. Int)
trait FixedSizeOf[A] extends SizeOf[A] {
def fixedSize: Long
def sizeOf(a: A) …Run Code Online (Sandbox Code Playgroud) 注意:此问题与volatile,AtomicLong或所描述的用例中的任何感知缺陷无关.
鉴于以下内容:
- 最近的64位OpenJDK 7/8(最好7位,但8位也很有帮助)
- 多处理英特尔基础系统
- 非易失性长原始变量
- 多个不同步的mutator线程
- 一个不同步的观察者线程
观察者是否始终保证会遇到由变异线程写的完整值,或者是撕裂危险的单词?
此属性对于32位基元和64位对象引用是存在的,但是对于long和double,JLS不保证:
17.7.非原子对double和long的处理:
出于Java编程语言内存模型的目的,对非易失性long或double值的单次写入被视为两个单独的写入:每个32位一半写入一次.这可能导致线程从一次写入看到64位值的前32位,而从另一次写入看到第二次32位的情况.
但是抱着你的马:
[...]为了效率,这种行为是特定于实现的; Java虚拟机的实现可以自由地以原子方式或分两部分执行对long和double值的写入.鼓励Java虚拟机的实现避免在可能的情况下拆分64位值.[...]
因此,JLS 允许 JVM实现拆分64位写入,并鼓励开发人员相应地进行调整,但也鼓励 JVM实现者坚持使用64位写入.我们还没有回答最新版本的HotSpot.
由于单词撕裂最有可能发生在紧密循环和其他热点的范围内,我试图分析JIT编译的实际汇编输出.长话短说:需要进一步测试,但我只能在long上看到原子64位操作.
我使用了hdis,一个OpenJDK的反汇编插件.在我老化的OpenJDK 7u25版本中构建并安装了插件之后,我开始编写一个简短的程序:
public class Counter {
static long counter = 0;
public static void main(String[] _) {
for (long i = (long)1e12; i < (long)1e12 + 1e5; i++)
put(i);
System.out.println(counter);
}
static void put(long v) {
counter += v;
}
}
Run Code Online (Sandbox Code Playgroud)
我确保始终使用大于MAX_INT(1e12到1e12 + 1e5)的值,并重复操作足够的次数(1e5)以触发JIT.
编译后,我用hdis执行Counter.main(),如下所示:
java -XX:+UnlockDiagnosticVMOptions \
-XX:PrintAssemblyOptions=intel \
-XX:CompileCommand=print,Counter.put …Run Code Online (Sandbox Code Playgroud) 对于不应暂停超过200毫秒的软实时系统的环境,我们正在寻找一种在完全GC即将发布之前预先发出警告的方法.我们意识到我们可能无法避免它,但我们想在系统停止之前故障转移到另一个节点.
我们已经能够提出一个方案,在即将完成的GC之前提供预警,这可能导致系统停滞几秒钟(我们需要避免).
我们能够提出的依赖于CMS免费列表统计:-XX:PrintFLSStatistics=1.这会在每个GC周期(包括年轻GC)之后将空闲列表统计信息打印到GC日志中,因此信息可以短时间间隔获得,并且在高内存分配率的间隔期间更频繁地出现.它在性能方面可能会花费一点点,但我们的工作假设是我们可以负担得起.
日志的输出如下所示:
Statistics for BinaryTreeDictionary:
------------------------------------
Total Free Space: 382153298
Max Chunk Size: 382064598
Number of Blocks: 28
Av. Block Size: 13648332
Tree Height: 8
Run Code Online (Sandbox Code Playgroud)
特别是,最大空闲块大小为382064598个单词.使用64位字,这应该低于2915MB.这个数字一直在缓慢下降,速度大约为每小时1MB.
我们的理解是,只要最大空闲块大小大于年轻代(假设没有大量的对象分配),每个对象促销都应该成功.
最近,我们进行了为期数天的压力测试,并且已经看到CMS能够将最大块大小保持在旧区域总空间的94%以上.最大的免费块大小似乎以小于1MB /小时的速度递减,这应该没问题 - 据此我们不会很快就达到完全GC,并且服务器可能会因维护更多而停机经常比完整的GC可能发生.
在之前的测试中,当系统内存效率较低时,我们已经能够运行系统10小时.在第一个小时内,最大免费块大小减少到100MB,并且停留超过8小时.在运行的最后40分钟内,当一个完整的GC发生时,最大空闲块大小以稳定的速率向0降低 - 这非常令人鼓舞,因为对于那个工作负载,我们似乎能够提前40分钟警告(当块大小开始稳定下降为0时).
我的问题是:假设这一切都反映了长时间的峰值工作量(生产中任何给定时间点的工作量只会更低),这听起来像是一种有效的方法吗?您认为我们应该能够依靠GC日志中的最大空闲块大小统计量来确定可靠性的程度吗?
我们绝对愿意接受建议,但要求他们仅限于HotSpot上的解决方案(No Azul对我们来说,至少目前为止).此外,G1本身并不是解决方案,除非我们能够提出类似的指标,以便在Full GCs之前提前发出警告,或者任何明显超过我们SLA的GC(这些可能偶尔发生).
java ×2
concurrency ×1
implicit ×1
jvm ×1
jvm-hotspot ×1
performance ×1
real-time ×1
scala ×1
scalaz ×1
typeclass ×1