├── .gitignore ├── README.md ├── README_zh.md ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── jiang │ │ └── json │ │ └── benchmark │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── jiang │ │ │ └── json │ │ │ └── benchmark │ │ │ └── MainActivity.kt │ └── res │ │ ├── drawable │ │ ├── ic_launcher_background.xml │ │ └── ic_launcher_foreground.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── values-night │ │ └── themes.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ │ └── xml │ │ ├── backup_rules.xml │ │ └── data_extraction_rules.xml │ └── test │ └── java │ └── com │ └── jiang │ └── json │ └── benchmark │ └── ExampleUnitTest.kt ├── benchmark ├── .gitignore ├── benchmark-proguard-rules.pro ├── build.gradle.kts └── src │ ├── androidTest │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── jiang │ │ └── json │ │ └── benchmark │ │ ├── JsonStreamBenchmark.kt │ │ ├── JsonStringBenchmark.kt │ │ └── KudosBenchmark.kt │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── jiang │ │ └── json │ │ └── benchmark │ │ ├── DataClassResponseModels.kt │ │ ├── JSONObjectSerializer.kt │ │ ├── JSONReaderSerializer.kt │ │ ├── KSResponseModels.kt │ │ ├── KudosGsonResponseModels.kt │ │ ├── KudosJacksonResponseModels.kt │ │ ├── KudosJsonReaderResponseModels.kt │ │ ├── MoshiResponseModels.kt │ │ ├── ResponseModels.kt │ │ └── SomeMessageOuterClass.java │ ├── proto │ └── SomeMessage.proto │ └── resources │ ├── large.bin │ ├── large.json │ ├── medium.bin │ ├── medium.json │ ├── small.bin │ └── small.json ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle.kts /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | .idea 4 | /local.properties 5 | /.idea/caches 6 | /.idea/libraries 7 | /.idea/modules.xml 8 | /.idea/workspace.xml 9 | /.idea/navEditor.xml 10 | /.idea/assetWizardSettings.xml 11 | .DS_Store 12 | /build 13 | /captures 14 | .externalNativeBuild 15 | .cxx 16 | local.properties 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | English | **[简体中文](README_zh.md)** 2 | 3 | # json-benchmark 4 | - Use the Jetpack Microbenchmark library for benchmark testing to avoid the impact of CPU frequency reduction and JIT optimization on test results. 5 | - The test case input includes three json files of size 12kb, 78kb, and 238kb to test the impact of json size on deserialization speed. 6 | - The test results are divided into multiple runs with sufficient preheating and one run without preheating to test the difference in deserialization speed under cold start. 7 | 8 | ## Test results 9 | ### Multi-run test results 10 | | | small json | medium json | large json | 11 | |----------------------|----------------|----------------|----------------| 12 | | Kotlin Serialization | 165,936 ns | 997,228 ns | 2,933,098 ns | 13 | | JSONReader | 190,902 ns | 1,164,605 ns | 3,412,914 ns | 14 | | FastJson | 196,860 ns | 1,417,077 ns | 4,218,987 ns | 15 | | JSONObject | 258,789 ns | 1,690,190 ns | 4,788,937 ns | 16 | | Moshi | 303,056 ns | 1,411,364 ns | 3,955,789 ns | 17 | | Gson | 412,421 ns | 1,356,564 ns | 3,557,943 ns | 18 | | Jackson | 1,073,504 ns | 1,798,989 ns | 3,543,983 ns | 19 | 20 | 21 | ![](https://raw.gitmirror.com/RicardoJiang/resource/main/2023/october/DeserializationSpeedMultiTimes.png) 22 | 23 | ### One-run test results 24 | | | small json | medium json | large json | 25 | |----------------------|-----------------|-----------------|-----------------| 26 | | Kotlin Serialization | 4,114,323 ns | 15,739,688 ns | 17,428,906 ns | 27 | | JSONReader | 630,469 ns | 2,052,501 ns | 5,630,261 ns | 28 | | FastJson | 61,629,844 ns | 6,756,823 ns | 10,529,791 ns | 29 | | JSONObject | 580,469 ns | 2,227,290 ns | 6,311,667 ns | 30 | | Moshi | 4,460,886 ns | 13,854,792 ns | 18,951,198 ns | 31 | | Gson | 3,319,688 ns | 5,568,906 ns | 10,264,635 ns | 32 | | Jackson | 15,070,469 ns | 13,625,521 ns | 17,914,687 ns | 33 | 34 | 35 | ![](https://raw.gitmirror.com/RicardoJiang/resource/main/2023/october/DeserializationSpeedRunOnce.png) 36 | 37 | ## Kudos test results 38 | [Kudos](https://github.com/kanyun-inc/Kudos) is short for Kotlin utilities for deserializing objects. It is designed to make it safer and easier to deserializing Kotlin classes with Gson and Jackson. 39 | 40 | Based on the working mechanism of Kudos, it is not difficult to think that the running time of Kudos will be slightly longer than the corresponding JSON serialization framework. The following is a comparison of the running time of Kudos and the corresponding JSON serialization framework: 41 | 42 | ### Multi-run test results 43 | | | small json | medium json | large json | 44 | |------------------|----------------|----------------|----------------| 45 | | Gson | 412,375 ns | 1,374,838 ns | 3,641,904 ns | 46 | | Kudos-Gson | 517,123 ns | 1,686,568 ns | 4,311,910 ns | 47 | | Jackson | 1,035,010 ns | 1,750,709 ns | 3,450,974 ns | 48 | | Kudos-Jackson | 1,261,026 ns | 2,030,874 ns | 3,939,600 ns | 49 | | JsonReader | 190,302 ns | 1,176,479 ns | 3,464,174 ns | 50 | | Kudos-JsonReader | 215,974 ns | 1,359,587 ns | 4,019,024 ns | 51 | 52 | ### One-run test results 53 | | | small json | medium json | large json | 54 | |------------------|-----------------|-----------------|-----------------| 55 | | Gson | 3,974,219 ns | 4,666,927 ns | 8,271,355 ns | 56 | | Kudos-Gson | 4,531,718 ns | 6,244,479 ns | 11,160,782 ns | 57 | | Jackson | 12,821,094 ns | 13,930,625 ns | 15,989,791 ns | 58 | | Kudos-Jackson | 13,233,750 ns | 15,674,010 ns | 18,641,302 ns | 59 | | JsonReader | 662,032 ns | 2,056,666 ns | 4,624,687 ns | 60 | | Kudos-JsonReader | 734,907 ns | 2,362,010 ns | 6,212,917 ns | 61 | 62 | ## More 63 | [Performance comparison of commonly used JSON libraries](https://android-performance-optimization.github.io/practical/speed/json-serialization-speed/) 64 | 65 | 66 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | **[English](README.md)** | 简体中文 2 | 3 | # json-benchmark 4 | - 通过 Jetpack Microbenchmark 库进行基准测试,以避免 CPU 降频,JIT 优化对测试结果的影响 5 | - 测试用例输入包括 12kb, 78kb, 238kb 大小的三个 json 文件,以测试 json 大小对反序列化速度的影响 6 | - 测试结果分为多次运行充分预热与一次运行无预热两种情况,以测试在冷启动情况下反序列化速度的差异 7 | 8 | ## 测试结果 9 | ### 多次运行测试结果 10 | | | small json | medium json | large json | 11 | |----------------------|----------------|----------------|----------------| 12 | | Kotlin Serialization | 165,936 ns | 997,228 ns | 2,933,098 ns | 13 | | JSONReader | 190,902 ns | 1,164,605 ns | 3,412,914 ns | 14 | | FastJson | 196,860 ns | 1,417,077 ns | 4,218,987 ns | 15 | | JSONObject | 258,789 ns | 1,690,190 ns | 4,788,937 ns | 16 | | Moshi | 303,056 ns | 1,411,364 ns | 3,955,789 ns | 17 | | Gson | 412,421 ns | 1,356,564 ns | 3,557,943 ns | 18 | | Jackson | 1,073,504 ns | 1,798,989 ns | 3,543,983 ns | 19 | 20 | 21 | ![](https://raw.gitmirror.com/RicardoJiang/resource/main/2023/october/DeserializationSpeedMultiTimes.png) 22 | 23 | ### 一次运行测试结果 24 | | | small json | medium json | large json | 25 | |----------------------|-----------------|-----------------|-----------------| 26 | | Kotlin Serialization | 4,114,323 ns | 15,739,688 ns | 17,428,906 ns | 27 | | JSONReader | 630,469 ns | 2,052,501 ns | 5,630,261 ns | 28 | | FastJson | 61,629,844 ns | 6,756,823 ns | 10,529,791 ns | 29 | | JSONObject | 580,469 ns | 2,227,290 ns | 6,311,667 ns | 30 | | Moshi | 4,460,886 ns | 13,854,792 ns | 18,951,198 ns | 31 | | Gson | 3,319,688 ns | 5,568,906 ns | 10,264,635 ns | 32 | | Jackson | 15,070,469 ns | 13,625,521 ns | 17,914,687 ns | 33 | 34 | 35 | ![](https://raw.gitmirror.com/RicardoJiang/resource/main/2023/october/DeserializationSpeedRunOnce.png) 36 | 37 | ## Kudos 测试结果 38 | [Kudos](https://github.com/kanyun-inc/Kudos) 是 Kotlin utilities for deserializing objects 的缩写。它可以解决使用 Gson、Jackson 等框架反序列化 JSON 到 Kotlin 类时所存在的空安全问题和构造器默认值失效的问题。 39 | 40 | 基于 Kudos 的工作机制不难想到,Kudos 的运行耗时会略微多于对应的 JSON 序列化框架。下面是 Kudos 与对应的 JSON 序列化框架的运行耗时对比。 41 | 42 | ### 多次运行测试结果 43 | | | small json | medium json | large json | 44 | |------------------|----------------|----------------|----------------| 45 | | Gson | 412,375 ns | 1,374,838 ns | 3,641,904 ns | 46 | | Kudos-Gson | 517,123 ns | 1,686,568 ns | 4,311,910 ns | 47 | | Jackson | 1,035,010 ns | 1,750,709 ns | 3,450,974 ns | 48 | | Kudos-Jackson | 1,261,026 ns | 2,030,874 ns | 3,939,600 ns | 49 | | JsonReader | 190,302 ns | 1,176,479 ns | 3,464,174 ns | 50 | | Kudos-JsonReader | 215,974 ns | 1,359,587 ns | 4,019,024 ns | 51 | 52 | ### 一次运行测试结果 53 | | | small json | medium json | large json | 54 | |------------------|-----------------|-----------------|-----------------| 55 | | Gson | 3,974,219 ns | 4,666,927 ns | 8,271,355 ns | 56 | | Kudos-Gson | 4,531,718 ns | 6,244,479 ns | 11,160,782 ns | 57 | | Jackson | 12,821,094 ns | 13,930,625 ns | 15,989,791 ns | 58 | | Kudos-Jackson | 13,233,750 ns | 15,674,010 ns | 18,641,302 ns | 59 | | JsonReader | 662,032 ns | 2,056,666 ns | 4,624,687 ns | 60 | | Kudos-JsonReader | 734,907 ns | 2,362,010 ns | 6,212,917 ns | 61 | 62 | ## 更多 63 | [常用 JSON 库性能对比](https://android-performance-optimization.github.io/practical/speed/json-serialization-speed/) -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.application") 3 | id("org.jetbrains.kotlin.android") 4 | } 5 | 6 | android { 7 | namespace = "com.jiang.json.benchmark" 8 | compileSdk = 33 9 | 10 | defaultConfig { 11 | applicationId = "com.jiang.json.benchmark" 12 | minSdk = 24 13 | targetSdk = 33 14 | versionCode = 1 15 | versionName = "1.0" 16 | 17 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 18 | } 19 | 20 | buildTypes { 21 | release { 22 | isMinifyEnabled = false 23 | proguardFiles( 24 | getDefaultProguardFile("proguard-android-optimize.txt"), 25 | "proguard-rules.pro" 26 | ) 27 | } 28 | } 29 | compileOptions { 30 | sourceCompatibility = JavaVersion.VERSION_1_8 31 | targetCompatibility = JavaVersion.VERSION_1_8 32 | } 33 | kotlinOptions { 34 | jvmTarget = "1.8" 35 | } 36 | } 37 | 38 | dependencies { 39 | 40 | implementation("androidx.core:core-ktx:1.9.0") 41 | implementation("androidx.appcompat:appcompat:1.6.1") 42 | implementation("com.google.android.material:material:1.8.0") 43 | implementation("androidx.constraintlayout:constraintlayout:2.1.4") 44 | testImplementation("junit:junit:4.13.2") 45 | androidTestImplementation("androidx.test.ext:junit:1.1.5") 46 | androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") 47 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/com/jiang/json/benchmark/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.jiang.json.benchmark 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.jiang.json.benchmark", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/jiang/json/benchmark/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.jiang.json.benchmark 2 | 3 | import androidx.appcompat.app.AppCompatActivity 4 | import android.os.Bundle 5 | 6 | class MainActivity : AppCompatActivity() { 7 | override fun onCreate(savedInstanceState: Bundle?) { 8 | super.onCreate(savedInstanceState) 9 | setContentView(R.layout.activity_main) 10 | } 11 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicardoJiang/json-benchmark/61d5664445f3fe5f5bf16e695454a482e00b98e6/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicardoJiang/json-benchmark/61d5664445f3fe5f5bf16e695454a482e00b98e6/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicardoJiang/json-benchmark/61d5664445f3fe5f5bf16e695454a482e00b98e6/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicardoJiang/json-benchmark/61d5664445f3fe5f5bf16e695454a482e00b98e6/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicardoJiang/json-benchmark/61d5664445f3fe5f5bf16e695454a482e00b98e6/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicardoJiang/json-benchmark/61d5664445f3fe5f5bf16e695454a482e00b98e6/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicardoJiang/json-benchmark/61d5664445f3fe5f5bf16e695454a482e00b98e6/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicardoJiang/json-benchmark/61d5664445f3fe5f5bf16e695454a482e00b98e6/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicardoJiang/json-benchmark/61d5664445f3fe5f5bf16e695454a482e00b98e6/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicardoJiang/json-benchmark/61d5664445f3fe5f5bf16e695454a482e00b98e6/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FF000000 4 | #FFFFFFFF 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | json-benchmark 3 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 |