面接で遭遇する問題を解決するために、JVM 仮想マシン (メモリ、ガベージ コレクション、パフォーマンスの最適化) を 1 つの記事で理解する

面接で遭遇する問題を解決するために、JVM 仮想マシン (メモリ、ガベージ コレクション、パフォーマンスの最適化) を 1 つの記事で理解する

[[285967]]

1. JVMメモリ領域の分割

1.1 Java仮想マシンのランタイムデータ領域

Java 仮想マシンのランタイム データ領域配布図:

  • JVM スタック (Java 仮想マシン スタック): Java では、各スレッドには対応するスレッド スタックがあります。スレッドごとに実行ロジックが異なるため、独立したスレッド スタックが必要です。したがって、スタックに格納される情報は、ローカル変数、プログラムの実行状態、メソッドの戻り値、メソッドの終了など、現在のスレッド (またはプログラム) に関連するものです。各メソッドが呼び出されてから実行されるまでのプロセスは、スタック フレームが仮想マシン スタックにプッシュされてからスタックからポップされるまでのプロセスに対応します。
  • ヒープ: ヒープはすべてのスレッドで共有され、主にオブジェクト インスタンスと配列を格納するために使用されます。物理的に不連続なメモリ空間でも、論理的に連続している限り
  • メソッド領域: 仮想マシンによってロードされたクラス情報、定数、静的変数、ジャストインタイムコンパイラによってコンパイルされたコードを格納する共有メモリ領域です。
  • 定数プール (ランタイム定数プール): メソッド領域の一部であり、コンパイル中に生成されるさまざまなリテラルとシンボリック参照を格納するために使用されます。
  • ネイティブ メソッド スタック:

これらのうち、ヒープと JVM スタックは、次の理由によりプログラム操作の鍵となります。

  1. スタックは実行時間(プログラムの動作、つまりプログラムの実行方法やデータ処理方法の問題を解決する)の単位であり、ヒープはストレージ(データストレージ、つまりデータをどのようにどこに置くかの問題を解決する)の単位です。
  2. ヒープにはオブジェクトが格納されます。スタックはヒープ内の基本データ型とオブジェクトへの参照を格納します。 (値渡しと参照渡しのパラメータ)

では、なぜヒープとスタックを区別するのでしょうか?スタックにデータを保存できないのですか?

  1. ソフトウェア設計の観点から見ると、スタックは処理ロジックを表し、ヒープはデータを表します。明確な分業と処理ロジックにより、「分割統治」と「分離」の考え方がより明確に体現されます。
  2. ヒープとスタックを分離することで、ヒープの内容を複数のスタックで共有できるようになります (これは、複数のスレッドが同じオブジェクトにアクセスするとも考えられます)。この共有方法には多くの利点があります。共有メモリなどのデータと対話するための効率的な方法を提供します。ヒープ内の共有定数とキャッシュはすべてのスタックからアクセスできるため、スペースを節約できます。
  3. システム操作のコンテキストを保存するなど、実行時のニーズにより、スタックをアドレス セグメントに分割する必要があります。スタックは上方向にしか成長できないため、スタックのコンテンツ保存能力が制限されます。ヒープが異なります。ヒープ内のオブジェクトは必要に応じて動的に増加します。したがって、スタックとヒープが分離されることにより、動的な拡張が可能になります。対応するスタックはヒープ内のアドレスを記録するだけで済みます。
  4. ヒープとスタックの組み合わせは、オブジェクト指向設計を完璧に体現しています。オブジェクトを逆アセンブルすると、オブジェクトの属性がデータであり、ヒープ内に格納されていることがわかります。オブジェクトの動作 (メソッド) は実行中のロジックであり、スタックに配置されます。したがって、オブジェクトを記述するときは、実際にはデータ構造とデータを処理するロジックの両方を記述することになります。

1.2 ヒープと JVM スタック:

1.2.1 ヒープ

Java ヒープは、Java 仮想マシンによって管理される最大のメモリ空間です。物理的には不連続なメモリ空間にありますが、論理的には連続していれば十分です。主にさまざまなクラスのインスタンス オブジェクトを格納するために使用されます。この領域はすべてのスレッドで共有され、仮想マシンの起動時に作成されます。オブジェクトインスタンスを保存するために使用されます。ほぼすべてのオブジェクトと配列はここでメモリを割り当てます (スタック割り当てとスカラー置換最適化テクノロジを除く)。

Java では、ヒープは若い世代 (Young) と古い世代 (Old) の 2 つの異なる領域に分割されます。ヤングジェネレーションは、エデン、From Survivor (S0)、To Survivor (S1) の 3 つのエリアに分かれています。図に示すように:

ヒープのメモリレイアウト:

この分割の目的は、メモリの割り当てや回復など、JVM がメモリ内のオブジェクトをより適切に管理できるようにすることです。新世代はエデンと2人の生存者に分かれます。

  • 有効スペースが拡大し、エデン+1 サバイバー。
  • オブジェクト生成の計算に役立ちます。オブジェクトが S0/S1 で設定された XX:MaxTenuringThreshold 値に達すると、そのオブジェクトは古い世代に移動されます。つまり、スキャンする必要があるのは 1 つの残存オブジェクトのみです。 S0/S1 がなく、オブジェクトが直接 2 つの領域に分割されている場合、オブジェクトが解放されずに GC を通過した回数を計算する方法。
  • 2つのサバイバーゾーンがメモリの断片化を解決します

1.2.2 スタック関連のパラメータ

注: ヒープ サイズは各 GC 後に調整されます。動的な調整によるパフォーマンスの低下を防ぐために、-Xms と -Xmx は通常同じに設定されます。

新世代の 3 つの設定パラメータの優先順位: -Xmn、-XX:NewSize、-XX:NewRatio:

1)。最高優先度: -XX:NewSize=1024m および -XX:MaxNewSize=1024m

2)。 2 番目に高い優先度: -Xmn1024m (デフォルトの同等の効果: -XX:NewSize==-XX:MaxNewSize==1024m)

3)。最低優先度: -XX:NewRatio=2

推奨されるパラメータは -Xmn です。これは非常に簡潔であり、NewSize と MaxNewSIze を一度に設定するのと同じであり、2 つが等しいためです。

1.3 JVM オブジェクト

1.3.1 オブジェクトの作成方法

各メソッドの実際の動作は次のとおりです。

1.3.2 JVMオブジェクトの割り当て

仮想マシン レベルでオブジェクトを作成する手順:

1.3.3 オブジェクトメモリ割り当て方法

オブジェクト メモリを割り当てるには、ポインタ衝突とフリー リストの 2 つの方法があります。

1) メモリが通常の場合は、仮想マシンはポインター衝突メソッド (Bump The Pointer) を使用してオブジェクトにメモリを割り当てます。つまり、使用済みのメモリはすべて片側にあり、空きメモリは反対側にあり、分割ポイントを示すポインタが中央にあります。メモリを割り当てるには、オブジェクトのサイズに等しい距離だけポインタを空き領域に移動するだけです。ガベージ コレクターが Serial や ParNew などの圧縮ベースのアルゴリズムを選択した場合、仮想マシンはこの割り当て方法を使用します。一般的に、ポインター衝突は、圧縮プロセスでコレクターを使用する場合に使用されます。

2) メモリが規則的ではなく、使用済みメモリと未使用メモリが混在している場合、仮想マシンはフリーリスト方式を使用してオブジェクトにメモリを割り当てます。つまり、仮想マシンは使用可能なメモリ ブロックを記録するためのリストを維持します。再割り当て時に、オブジェクト インスタンスに割り当てるのに十分な大きさの領域をリストから見つけ、リスト内のコンテンツを更新します。この割り当て方法は「フリーリスト」と呼ばれます。

注: 割り当て方法の選択は、Java ヒープが通常かどうかによって決まります。また、Java ヒープが通常かどうかは、使用するガベージ コレクターに圧縮機能があるかどうかによって決まります。

1.3.4 どのようなオブジェクトが古い世代に入ることができますか?

1.4 メモリの割り当てとリサイクル戦略

オブジェクトは最初に Eden に割り当てられます。ほとんどの場合、オブジェクトは新世代の Eden 領域に割り当てられます。 Eden 領域に割り当てるための十分なスペースがない場合、仮想マシンはマイナー GC を開始します。仮想マシンは、ガベージコレクションが発生したときにメモリ回復ログを印刷し、プロセス終了時に現在のメモリの各領域の割り当て状態を出力するための -XX:PrintGCDetails パラメータを提供します。

大きなオブジェクトは古い世代に直接送られます。いわゆるラージ オブジェクトとは、大量の連続したメモリ領域を必要とする Java オブジェクトを指します。最も一般的な大きなオブジェクトは、非常に長い文字列と配列です。仮想マシンは -XX:PretenureSizeThreshold パラメータを提供しており、この値より大きいオブジェクトを旧世代に直接割り当てることができます (この目的は、Eden 領域と 2 つの Survivor 間で大量のメモリ コピーを回避することです)。

長期間存続するオブジェクトは、古い世代のオブジェクト年齢カウンターに直接移動します。 -XX:最大テンリングしきい値

動的なオブジェクトの年齢の決定: 仮想マシンでは、オブジェクトを古い世代に昇格させる前に、必ずしもオブジェクトの年齢が MaxTenuringThreshold に達する必要はありません。 Survivor スペース内の同じ年齢のすべてのオブジェクトのサイズの合計が Survivor スペースの半分より大きい場合、その年齢以上のオブジェクトは、MaxTenuringThreshold で必要な年齢を待たずに、直接古い世代に入ることができます。

スペース割り当ての保証: マイナー GC が発生する前 (または発生後) に、仮想マシンは、以前の古い世代への昇格の平均サイズ (その時点で存続するオブジェクトの数が不確かなため、以前の平均値/経験値が採用される) が、古い世代の残りのスペース サイズより大きいかどうかを確認します。その場合は、代わりにフル GC が直接実行されます。小さい場合は、HandlePromotionFailure 設定で失敗の保証が許可されているかどうかを確認します。許可されている場合は、マイナー GC のみが実行されます。許可されていない場合は、代わりにフル GC も実行されます。比較のために平均値を取ることは、依然として動的確率法です。つまり、マイナー GC を生き残るオブジェクトの数が突然増加し、平均値よりもはるかに多い場合、それでも保証障害 (Handle Promotion Failure) が発生し、フル GC がトリガーされます。

2.1 参考文献 2 ガベージコレクションアルゴリズムの分類

2.2 GCルートオブジェクト

2.3 マークスイープ

これは、現代のガベージ コレクション アルゴリズムの思想的基礎と見なされています。

マーク アンド スイープ アルゴリズムは、上の図に示すように、ルート セットからスキャンし、生き残ったオブジェクトをマークしてから、スペース全体でマークされていないオブジェクトをスキャンしてリサイクルします。マークスイープ アルゴリズムでは、オブジェクトの移動は必要なく、デッド オブジェクトのみを処理します。ライブオブジェクトが多数ある場合に非常に効率的です。ただし、マークスイープ アルゴリズムは使用済みのオブジェクトを直接リサイクルするため、メモリの断片化が発生します。

2.4 コピーアルゴリズム

このアルゴリズムは、ハンドルのオーバーヘッドを克服し、ヒープ断片化のガベージコレクションを解決するために提案されました。これは、生きているオブジェクトが少なく、ガベージオブジェクトが多いという前提に基づいています。このアルゴリズムは、毎回使用中のオブジェクトのみを処理するため、コピーコストは比較的小さくなります。同時に、対応するメモリはコピー後にソートできるため、断片化の問題は発生しません。しかし、欠点も明らかです。つまり、メモリスペースが 2 倍必要になるということです。

最初にヒープをオブジェクト プレーンと複数のフリー プレーンに分割します。プログラムは、オブジェクト プレーンからオブジェクトにスペースを割り当てます。オブジェクトがいっぱいになると、コピー アルゴリズムに基づくガベージ コレクションがルート セットからアクティブ オブジェクトをスキャンし、各アクティブ オブジェクトを空きプレーンにコピーします (アクティブ オブジェクトによって占有されているメモリ間に空き領域がないようにするため)。このようにして、自由平面がオブジェクト平面になり、元のオブジェクト平面が自由平面になり、プログラムは新しいオブジェクト平面にメモリを割り当てます。対処アルゴリズムに基づく典型的なガベージ コレクションは、ヒープ領域をオブジェクト プレーンと空き領域プレーンに分割するストップ アンド コピー アルゴリズムです。オブジェクト平面と自由領域平面間の切り替え処理中は、プログラムの実行が中断されます。

2.5 Mark-Compact (または Mark-Compact、または MarkSweepCompact)

このアルゴリズムは、「マークアンドスイープ」と「コピーアルゴリズム」の利点を組み合わせたものです。 「マークアンドスイープ」の断片化問題と「コピー」アルゴリズムのスペース問題を回避します。

マークスイープ アルゴリズムは、マークスイープ アルゴリズムと同じ方法を使用してオブジェクトをマークしますが、クリアする場合は異なります。残存していないオブジェクトによって占有されているスペースを再利用した後、残存しているすべてのオブジェクトは左側の空きスペースに移動され、対応するポインターが更新されます。マークスイープアルゴリズムは、マークスイープアルゴリズムに基づいており、オブジェクトの移動も行うため、コストは高くなりますが、メモリの断片化の問題を解決します。コンパクト化アルゴリズムに基づくコレクターの実装では、通常、ハンドルとハンドル テーブルが追加されます。

2.6 世代を超えた収集

異なるオブジェクトのライフサイクルは異なるという事実に基づきます。したがって、ライフサイクルの異なるオブジェクトには異なるリサイクル アルゴリズムを採用して、リサイクル効率を向上させることができます。

新しい世代のオブジェクトの生存時間は短く、頻繁な GC が必要なため、より効率的なレプリケーション アルゴリズムが使用されます。メモリ領域は、1 つのエデン領域と 2 つのサバイバー領域に分かれています。エデンエリアとサバイバーエリアのデフォルトの比率は 8:1 です。メモリを割り当てるときは、まずeden領域が割り当てられます。エデン領域がいっぱいになると、GC のレプリケーション アルゴリズムを使用して、生き残ったオブジェクトをサバイバー領域にコピーします。残存領域がいっぱいになると、残存オブジェクトは別の領域にコピーされます。オブジェクトの生存時間が一定のしきい値を超えると、そのオブジェクトは古い世代に配置されます。古い世代と永続的な世代では、オブジェクトが長期間存続するため、マークスイープ アルゴリズムまたはマークコンパクト アルゴリズムが使用されます。

要約:

新世代:レプリケーション アルゴリズム(新世代のリサイクルの頻度は非常に高く、各リサイクルには短い時間がかかります。高頻度の新世代のリサイクルをサポートするために、仮想マシンはカード テーブルと呼ばれるデータ構造を使用する場合があります。カード テーブルはビットのセットであり、各ビットを使用して、古い世代の特定の領域内のすべてのオブジェクトに新世代のペアがあるかどうかを示すことができます。

2.7 ガベージコレクター

ガベージ コレクターのタスクは、メモリのクリーンアップのためにガベージ オブジェクトを識別してリサイクルすることです。世代によって使用できるコレクターは異なります。

  • 新世代コレクターが使用するコレクター: Serial、ParNew、Parallel Scavenge。
  • 旧世代のコレクターが使用するコレクター: Serial Old (MSC)、Parallel Old、CMS。

要約:

  1. 旧世代から新世代まで、あらゆるシリアルコレクターにご利用いただけます。 CMS コレクターのバックアップ コレクターとしても使用できます。
  2. CMS は新世代の Serial および ParNew でのみ使用でき、ParNew は CMS のデフォルトの新世代コレクターです。
  3. 並列: 複数のガベージコレクションスレッドが並行して動作しているが、ユーザースレッドはまだ待機状態にあることを指します。
  4. 同時実行: ユーザー スレッドとガベージ コレクション スレッドが同時に実行されることを指します (ただし、必ずしも並列ではなく、交互に実行される場合もあります)。ユーザー プログラムは実行を継続しますが、ガベージ コレクション プログラムは別の CPU で実行されます。

3. GC実行メカニズム

Java のヒープ (deap) も、GC がガベージを収集する主な領域です。オブジェクトは世代ごとに処理されるため、ガベージコレクションの領域と時間も異なります。 GC には、スカベンジ GC (マイナー GC) とフル GC (メジャー GC) の 2 種類があります。

  • Scavenge GC (マイナー GC): 通常、新しいオブジェクトが生成され (age=0)、Eden 内のスペースのアプリケーションが失敗すると、Scavenge GC がトリガーされ、Eden 領域で GC が実行され、存続していないオブジェクトがクリアされ、存続しているオブジェクトが Survivor 領域 (age+1) に移動します。次に、2 つのサバイバー エリアを整理します (実際には、コピーしながら整理します)。このタイプの GC は若い世代の Eden 領域で実行され、古い世代には影響しません。ほとんどのオブジェクトは Eden 領域から開始され、Eden 領域はそれほど大きく割り当てられていないため、Eden 領域の GC は頻繁に実行されます。したがって、一般的には、Eden をできるだけ早く解放するために、高速で効率的なアルゴリズム (つまり、コピークリーン アルゴリズム) を使用する必要があります。 Java のほとんどのオブジェクトは通常、長期間存続する必要がなく、本質的に一時的なものです。
  • フル GC: Young、Tenured、Perm を含むヒープ全体を照合します。フル GC はペア全体をリサイクルする必要があるため、スカベンジ GC よりも遅くなります。したがって、Full GC の回数は可能な限り減らす必要があります。 JVM チューニングのプロセスでは、FullGC を調整する作業が大部分を占めます。

3.1 フルGC実行をトリガーするシナリオ

3.2 Young GCのトリガー条件

3.3 新しいオブジェクトのGC回復プロセス

新しく作成されたオブジェクトのほとんどが GC で再利用されるという前提に基づいています。新世代の GC では、コピー アルゴリズムが使用されます (若い世代は 3 つの部分に分かれており、主にライフ サイクルの短いオブジェクトをできるだけ若い世代に保持します。古い世代には、キャッシュなどのライフ サイクルの長いオブジェクトが主に格納されます)。可能なプロセス:

  1. オブジェクトが作成されると、メモリの割り当ては通常、Eden 領域で完了します (いくつかの例外があります)。
  2. Eden 領域がいっぱいの場合、オブジェクトを作成すると、スペースを割り当てることができないためマイナー GC がトリガーされ、若い (eden+1survivor) 領域のガベージ コレクションが実行されます。
  3. マイナー GC 中、Eden および Survivor A 内のオブジェクトのうち、GC によって回収できず、経過時間がしきい値 (tenuring しきい値) に達していないものは Survivor B に配置され、常に 1 つの Survivor が空になるようにします。
  4. ステップ 3 を実行するときに、残存領域がいっぱいであることが判明した場合、これらのオブジェクトは古い領域にコピーされます (割り当て保証メカニズム)。または、残存領域がいっぱいではないが、一部のオブジェクトが十分に古い場合、それらも古い領域 XX:MaxTenuringThreshold に配置されます。 (古い世代に入っているオブジェクトの状況を確認する)
  5. エデンとサバイバーAを直接クリアします。
  6. Old 領域がいっぱいになると、フル GC が実行されます。

3.4 GCログ

GC ログ関連のパラメータ:

  • -XX:+PrintGC: GCログを出力する
  • -XX:+PrintGCDetails: GCの詳細なログを出力する
  • -XX:+PrintGCTimeStamps: GCタイムスタンプを出力します(ベースタイムの形式で)
  • -XX:+PrintGCApplicationStoppedTime: ガベージコレクション中にプログラムが一時停止された時間を出力します
  • -XX:+PrintGCApplicationConcurrentTime: 各ガベージコレクションの前にプログラムの中断のない実行時間を出力します。
  • -XX:+PrintHeapAtGC: GC の前後のヒープ情報を出力します
  • -XX:+PrintTLAB: TLABスペースの使用状況を確認します
  • -XX:PrintTenuingDistribution: 各マイナーGC後の新しい生存サイクルしきい値を表示します
  • -XX:PrintReferenceFC: システム内のソフト参照 (softReference)、弱参照 (weadReference)、ファントム参照 (phantomReference) を追跡し、参照プロセスを表示するために使用されます。

ケーススタディ:

-XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime を一緒に使用する

アプリケーション時間: 0.3440086 秒 アプリケーション スレッドが停止した合計時間: 0.0620105 秒 アプリケーション時間: 0.2100691 秒 アプリケーション スレッドが停止した合計時間: 0.0890223 秒

アプリケーションは最初の 344 ミリ秒間は実際の作業を実行し、その後 62 ミリ秒間すべてのスレッドを一時停止し、さらに 210 ミリ秒間作業を実行し、その後さらに 89 ミリ秒間一時停止したことがわかります。

2796146K->2049K(1784832K)] 4171400K->2049K(3171840K)、[メタスペース: 3134K->3134K(1056768K)​​]、0.0571841 秒] [時間: ユーザー=0.02 システム=0.04、実=0.06 秒]アプリケーション スレッドが停止した合計時間: 0.0572646 秒、スレッドの停止にかかった時間: 0.0000088 秒

アプリケーション スレッドは、ガベージ コレクションを実行するために 57 ミリ秒間強制的に一時停止されました。このうち 8 ミリ秒は、すべてのアプリケーション スレッドが安全なポイントに到達するまで待機するために使用されます。

-XX:+PrintGCDetailsを設定すれば、自動的に-verbose:gcと-XX:+PrintGCが設定されます。

33.125: [GC [DefNew: 3324K->152K(3712K), 0.0025925 秒] 3324K->152K(11904K), 0.0031680 秒]100.667: [フル GC [Tenured: 0K->210K(10240K), 0.0149142 秒] 4603K->210K(19456K), [Perm: 2999K->2999K(21248K)], 0.0150007 秒] [時間: ユーザー=0.01 システム=0.00、実=0.02 秒]

  1. 最初の数字「33.125:」と「100.667:」は、GC が発生した時刻を表します。この数値は、Java 仮想マシンが起動されてから経過した秒数を意味します。
  2. GC ログの先頭にある「[GC」と「[Full GC」は、新世代の GC と旧世代の GC を区別するのではなく、このガベージ コレクションの一時停止の種類を示します。 「Full」がある場合は、この GC 中に Stop-The-World が発生したことを意味します。
  3. 続く「[DefNew」、「[Tenured」、「[Perm」」は、GC が発生する領域を示します。ここで表示される領域名は、使用される GC コレクターと密接に関連しています。たとえば、上記の例で使用されているシリアル コレクターの新しい世代は「Default New Generation」という名前が付けられているため、「[DefNew」と表示されます。 ParNew コレクターの場合、新しい世代の名前は「Parallel New Generation」を意味する「[ParNew」になります。 Parallel Scavenge コレクターが使用される場合、対応する新しい世代は「PSYoungGen」と呼ばれます。旧世代と永代世代でも同様です。名前もコレクターによって決定されます。
  4. 角括弧内の「3324K->152K(3712K)」は、「GC前のメモリ領域の使用容量 -> GC後のメモリ領域の使用容量(メモリ領域の総容量)」を意味します。角括弧の外側の「3324K->152K(11904K)」は、「GC 前の Java ヒープ使用容量 -> GC 後の Java ヒープ使用容量 (合計 Java ヒープ容量)」を意味します。
  5. さらに下の「0.0025925 秒」は、このメモリ領域の GC にかかった時間 (秒単位) を示します。より具体的な時間データを提供するコレクターもいる
  6. [Full GC 283.736: [ParNew: 261599K->261599K(261952K), 0.0000288 秒] 新世代コレクター ParNew のログにも "[Full GC" と表示されます (これは通常、割り当て保証の失敗などの問題が原因で、STW につながります)。 System.gc() メソッドの呼び出しによってコレクションがトリガーされた場合、ここに "[Full GC (System)" が表示されます。

3.5 GCオーバーヘッドを削減するための対策

コードから:

JVM パラメータのチューニングから:

3.6 メモリオーバーフローの分類

IV.概要 - JVM チューニング関連

4.1 チューニングの目的

4.2 JVMパフォーマンスチューニングのレベル

4.3 JVM チューニング プロセス

4.4 パフォーマンス監視ツール

チューニングの最終的な目標は、アプリケーションが最小限のハードウェア消費でより高いスループットを実現できるようにすることです。 JVM チューニングも例外ではありません。 JVM チューニングは主にガベージ コレクターの収集パフォーマンスを最適化し、仮想マシン上で実行されるアプリケーションが使用するメモリとレイテンシを削減して、スループットを向上させることを可能にします。

<<:  分散データベースの構築方法

>>:  クラウドネイティブの台頭に役立つ2020年のトップ8オープンソースツール

推薦する

プロメテウス VPS シンプルテスト

私は、前四半期のLEBでトップランクのVPSプロバイダーであるPrometeusからVPSを購入する...

中国の4G開発速度は3Gより速い

あっという間に、中国で4Gライセンスが発行されてから1年が経ちました。嬉しい驚きだったのは、3Gライ...

蒸しパンを買うのに14万元を誤って支払った理由:顧客が金額としてパスワードを入力した

最近、上都路と十里埔街の交差点にある汴良大湯餃子店の店長の何六柱さんは心配していることがある。×紅偉...

クラウドネイティブ時代にアプリケーションを安全に保つために自動化が重要な理由

過去 1 年間で、長年にわたり実装されてきたテクノロジー ロードマップの実現が加速し、デジタル変革を...

なぜウェブマスターはBaiduを批判したがるのでしょうか?

Baidu は検索分野とテクノロジーに非常に強い企業であり、今後さらに発展していくことは間違いありま...

豆腐販売業者はウェブサイトを構築することで大金を稼ぐことができるでしょうか? 業界ウェブサイトの重要性について語る

2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っています豆腐が好き...

Alipayのコンピュータ送金には手数料がかかります

Alipayは、2013年12月3日より、コンピューター上のAlipayアカウント間の送金に手数料が...

ローカルウェブサイト運営経験についての簡単な説明

私は長年、ローカル Web サイトに取り組んできました。今日は、ローカル Web サイトのオンライン...

ウェブサイトの共有ボタンを再設計する: ユーザーに気に入ってもらう方法

最近のほとんどのウェブサイトにはソーシャル共有ボタン機能が追加されており、これはほぼ分子拡散のトレン...

Javaマイクロサービスアーキテクチャとコンテナ化されたデプロイメントに関する深い理解

クラウド コンピューティングと大規模分散システムの台頭により、Java マイクロサービス アーキテク...

音楽ウェブサイトの有料化計画は著作権管理局から明確な支持を受けるが、オンライン視聴は引き続き無料

音楽ダウンロードの「無料ランチ」の終焉に関する最近の議論に関して、記者は昨日、テンセントのQQミュー...

Kステーションの上位10の理由のまとめ

皆さんは、以前の百度Kステーション事件に深い印象を持っていると思いますよね?医療業界のサイト、タオバ...

レスポンシブ デザインの実践: IE10 に最適化されたバージョン cnBeta の誕生

過去 2 年間で、多くのインターネット製品が、さまざまなデバイスやブラウザの制限を克服するためにレス...

大騒ぎするほどのことではないが、中国のクラウドファンディングの問題点とは何だろうか?

債務型クラウドファンディングP2Pの急速な発展に加えて、株式型クラウドファンディング、リターン型クラ...