JVM について他にわからないことはありますか? JVM を簡単に説明します。

JVM について他にわからないことはありますか? JVM を簡単に説明します。

  [[278722]]

仮想マシン

JVM = クラスローダー + 実行エンジン + ランタイムデータ領域

次の図は、一般的な JVM (JVM 仕様 Java SE 7 エディションに準拠) の主要な内部コンポーネントを示しています。

コンポーネントのマルチスレッド

「マルチスレッド」または「フリースレッド」とは、プログラムが複数のスレッドの操作を同時に実行できる機能を指します。マルチスレッド アプリケーションの例として、プログラムは 1 つのスレッドでユーザー入力を受け取り、別のスレッドでいくつかの複雑な計算を実行し、3 番目のスレッドでデータベースを更新します。シングルスレッド アプリケーションでは、ユーザーは計算またはデータベースの更新が完了するまで待機する時間がかかる場合があります。マルチスレッド アプリケーションでは、これらのプロセスはバックグラウンドで実行されるため、ユーザーの時間が無駄になりません。マルチスレッドは、コンポーネントプログラミングにおいて非常に強力なツールになります。マルチスレッド コンポーネントを記述することで、バックグラウンドで複雑な計算を実行するコンポーネントを作成し、計算の進行中にユーザー インターフェイス (UI) がユーザー入力に自由に応答できるようになります。マルチスレッドは強力なツールですが、正しく使用するのは難しいです。マルチスレッド コードが誤って実装されると、アプリケーションのパフォーマンスが低下したり、アプリケーションがフリーズしたりする可能性があります。次のトピックでは、マルチスレッド プログラミングに関する考慮事項とベスト プラクティスについて説明します。 .NET Framework には、コンポーネントのマルチスレッド化のためのいくつかのオプションが用意されています。 System.Threading 名前空間の関数は 1 つのオプションです。イベントベースの非同期パターンも別のオプションです。 BackgroundWorker コンポーネントは非同期パターンの実装です。使いやすさを考慮してコンポーネントにカプセル化された高度な機能を提供します。

JVM メモリ管理メカニズム

(1)メモリ領域とメモリオーバーフロー例外

(2)ガベージコレクタとメモリ割り当て戦略

(3)仮想マシンのパフォーマンス監視およびトラブルシューティングツール

JVM チューニング

1.JVM実行サブシステム

(1)クラスファイルの構造

(2)クラスローディング機構

(3)バイトコード実行エンジン

2. プログラムのコンパイルとコードの最適化

(1)コンパイル時の最適化

(2)ランタイム最適化

3. 実践的なチューニング事例とソリューション

JVM システムスレッド

jconsole またはその他のデバッグ ツールを使用して確認すると、バックグラウンドで多数のスレッドが実行されていることがわかります。これらの実行中のバックグラウンド スレッドには、public static void main(String[]) を実行する必要性に基づいて作成されるメイン スレッドは含まれません。これらのバックグラウンド スレッドはメイン スレッドによって作成されます。 HotspotJVM の主なバックグラウンド システム スレッドを次の表に示します。

シングルスレッド

各スレッドの実行は、次のコンポーネントで構成されます。

プログラムカウンタ (PC)

現在の命令またはオペコードがネイティブでない限り、現在の命令またはオペコードのアドレスは、アドレス指定のために PC に依存する必要があります。現在のメソッドがネイティブの場合、PC は未定義になります。すべての CPU には PC があり、通常、各命令の実行後に増分されて、次に実行される命令のアドレスを指します。 JVM は PC を使用して、実行されている命令の場所を追跡します。実際、PC はメソッド領域のメモリ アドレスを指すために使用されます。

ネイティブスタック

すべての JVM がネイティブ メソッドをサポートしているわけではありませんが、ネイティブ メソッドをサポートする JVM は通常、スレッドごとにネイティブ メソッド スタックを作成します。 C リンク モデルを使用して JVM の JNI (Java Native Invocation) を実装する場合、ネイティブ スタックも C で実装されたスタックになります。この例では、ネイティブ スタック内のパラメーターの順序と戻り値は、通常の C プログラムと同じになります。ネイティブ メソッドは通常、JVM へのコールバック (これは JVM 実装によって異なります) を行い、Java メソッドを実行します。このようなネイティブから Java への呼び出しはスタック (通常は Java スタック) 上で発生し、同時にスレッドもネイティブ スタックを離れ、通常は Java スタック上に新しいフレームを作成します。

スタック

各スレッドには独自のスタックがあり、スレッドで実行される各メソッドのフレームを格納するために使用されます。スタックは後入れ先出しのデータ構造であり、現在実行中のメソッドをスタックの一番上に配置できます。メソッドの実行ごとに、新しいフレームが作成され、スタックの先頭にプッシュされます。メソッドが正常に返されるか、メソッドの実行中にキャッチされない例外が発生すると、フレームがポップされます。フレーム オブジェクトのプッシュ/ポップを除き、スタックは直接操作されません。したがって、フレーム オブジェクトはヒープ上に割り当てられる可能性があり、メモリは必ずしも連続したアドレス空間である必要はないことがわかります (フレーム ポインタとフレーム オブジェクトの違いに注意してください)。

スタックの制限

スタックは動的または固定サイズにすることができます。スレッドがより大きなスタックを要求すると、StackOverflowError 例外がスローされます。スレッドが新しいフレームの作成を要求したが、それを割り当てるのに十分なメモリ領域がない場合は、OutOfMemoryError 例外がスローされます。

フレーム

メソッドの実行ごとに、新しいフレームが作成され、スタックの先頭にプッシュされます。メソッドが正常に返されるか、メソッドの実行中にキャッチされない例外が発生すると、フレームはスタックからポップされます。

ローカル変数配列

ローカル変数配列には、メソッドの実行中に使用されるすべての変数が含まれます。これ、すべてのメソッド パラメーター、およびその他のローカルに定義された変数への参照が含まれます。クラス メソッド (静的メソッドなど) の場合、メソッド パラメーターのストレージ インデックスは 0 から始まります。インスタンス メソッドの場合、インデックス 0 のスロットは this ポインターを格納するために予約されています。

オペランドスタック

オペランド スタックは、バイトコード命令の実行中に使用されます。これは、ネイティブ CPU で使用される汎用レジスタに似ています。バイトコードの大部分は、プッシュ、ポップ、コピー、スワップ、または値の生成/消費操作の実行によって、オペランド スタックとのやり取りに時間を費やします。バイトコードの場合、ローカル変数配列とオペランドスタック間で値を移動する命令が非常に頻繁に使用されます。

動的リンク

各フレームには、ランタイム定数プールへの参照が含まれています。この参照は、実行されるメソッドが属するクラスの定数プールを指します。この参照は動的リンクを支援するためにも使用されます。

Java クラスがコンパイルされると、クラスの定数プールに格納されている変数とメソッドへのすべての参照は、シンボリック参照として扱われます。シンボリック参照は単なる論理参照であり、最終的に物理メモリ アドレスを指す参照ではありません。 JVM 実装では、シンボリック参照をいつ解決するかを選択できます。これは、クラス ファイルが検証され、ロードされた後に発生する可能性があり、これは積極的分析または静的分析と呼ばれます。違いは、シンボリック参照が初めて使用されるときにも発生する可能性があることです。これは、遅延分析または遅延分析と呼ばれます。ただし、JVM では、各参照が初めて使用される前に解決が行われ、その時点で分析エラーが発生した場合に例外がスローされることを保証する必要があります。バインディングとは、シンボリック参照によって識別されるフィールド、メソッド、またはクラスを直接参照に置き換えるプロセスです。シンボル参照を完全に置き換える必要があるため、このプロセスは 1 回だけ実行されます。シンボリック参照がクラスを参照し、そのクラスがまだ解決されていない場合は、そのクラスもすぐにロードされます。各直接参照は、変数またはメソッドの実行時の場所に関連付けられた構造体へのオフセットとして保存されます。

スレッド間で共有

ヒープ

ヒープ内のノードの値は、常にその親ノードの値より大きくも小さくもありません。

ヒープは常に完全なバイナリ ツリーです。

最大のルート ノードを持つヒープは最大ヒープまたはビッグ ルート ヒープと呼ばれ、最小のルート ノードを持つヒープは最小ヒープまたはスモール ルート ヒープと呼ばれます。一般的なヒープには、バイナリ ヒープとフィボナッチ ヒープがあります。

ヒープ定義は次のとおりです: n 個の要素のシーケンス {k1、k2、ki、…、kn} は、次の関係を満たす場合にのみヒープと呼ばれます。

(ki <= k2i,ki <= k2i+1) または (ki >= k2i,ki >= k2i+1)、(i = 1,2,3,4...n/2)

このシーケンスに対応する 1 次元配列 (つまり、1 次元配列がこのシーケンスの格納構造として使用されている) を完全な二分木と見なすと、ヒープの意味は、完全な二分木内のすべての非終端ノードの値が、その左右の子ノードの値より大きくない (または小さくない) ことを示します。したがって、シーケンス {k1、k2、...、kn} がヒープである場合、ヒープの最上位要素 (または完全なバイナリ ツリーのルート) は、シーケンス内の n 個の要素の最小値 (または最大値) である必要があります。

非ヒープメモリ

一部のオブジェクトはヒープ内に作成されず、これらのオブジェクトは論理的には JVM メカニズムの一部であると見なされます。

非ヒープ メモリには次のものが含まれます。

  • 永久世代には以下が含まれます。
  • 方法領域
  • 内部文字列
  • コードキャッシュ: JIT コンパイルされたメソッドをネイティブコードにコンパイルして保存するために使用されます。

メモリ管理

オブジェクトと配列は明示的に解放されることはないため、ガベージ コレクターによってのみ自動的に回収されます。

通常、手順は次のとおりです。

  1. 新しいオブジェクトと配列は若い世代で作成される
  2. マイナー ガベージ コレクターは若い世代で実行されます。まだ生きているオブジェクトはエデンエリアからサバイバーエリアに移動されます
  3. メジャー ガベージ コレクターはオブジェクトを世代間で移動し、通常、メジャー ガベージ コレクターによってアプリケーションのスレッドが一時停止されます。まだ生きているオブジェクトは、若い世代から古い世代に移動されます。
  4. 古い世代がリサイクルされるたびに、永久世代もリサイクルされます。どちらかがいっぱいになるとリサイクルされます。

JIT コンパイル

JIT の具体的な操作は次のとおりです。型が読み込まれると、CLR は型の内部データ構造と対応する関数を作成します。関数が初めて呼び出されると、JIT は関数を機械語にコンパイルします。関数が再度実行されると、コンパイルされたマシン言語がキャッシュから直接実行されます。

方法領域

すべてのスレッドは同じメソッド領域を共有します。したがって、メソッド領域データへのアクセスと動的リンクの処理はスレッドセーフである必要があります。 2 つのスレッドが、まだロードされていないクラス (クラスは 1 回だけロードする必要があります) のフィールドまたはメソッドにアクセスしようとすると、クラスがロードされるまで 2 つのスレッドは実行を続行できません。

クラスファイルの構造

コンパイルされたクラス ファイルの構造は次のとおりです。

  1. クラスファイル
  2. { u4magic; u2マイナーバージョン; u2メジャーバージョン; u2定数プールカウント;
  3. cp_info定数プール[定数プール数 – 1]; u2access_flags;
  4. u2this_class; u2スーパークラス; u2インターフェイス数;
  5. u2interfaces[インターフェース数]; u2フィールド数;
  6. field_infoフィールド[フィールド数]; u2メソッドの数;
  7. method_infoメソッド[メソッド数]; u2属性の数;
  8. attribute_info属性[属性数];}

javap コマンドを使用して、コンパイルされた Java クラスのバイトコードを表示できます。

以下は、このクラス ファイルで使用されるオペコードのリストです。

他の一般的なバイトコードと同様に、上記のオペコードは主にローカル変数、オペランド スタック、およびランタイム定数プールを処理するために使用されます。

コンストラクターには 2 つの命令があり、最初の命令は「this」をオペランド スタックにプッシュし、次にコンストラクターの親コンストラクターが実行されて this が「消費」され、オペランド スタックからポップされます。

sayHello() メソッドに関しては、実行がより複雑になります。ランタイム定数プールを通じて、シンボリック参照を実際の参照に解決する必要があるためです。最初のオペランド getstatic は、System クラスから静的フィールドへの参照をオペランド スタックにプッシュするために使用されます。次のオペランド ldc は、文字列リテラル「Hello」をオペランド スタックにプッシュします。最後に、invokevirtual オペランドは System.out の println メソッドを実行し、オペランド スタックから "Hello" をパラメーターとしてポップし、現在のスレッドの新しいフレームを作成します。

高並列性、分散、Springソースコード、MyBatisソースコード、ビッグデータ、Nettyなどの技術的な知識ポイントの包括的なアーキテクチャビデオ資料

クラスローダー

JVM の起動は、ブートストラップ クラス ローダーを通じて初期化用のクラスをロードすることです。このクラスは、public static void main(String[]) が実行される前にリンクされ、インスタンス化されます。メイン メソッドを実行すると、追加の必要なクラスとインターフェイスが順番に読み込まれ、リンクされ、初期化されます。

ロード: ロードとは、クラスまたはインターフェース タイプを表すクラス ファイルを見つけて、それをバイト配列に読み込むプロセスです。次に、バイトが解析され、クラス オブジェクトを表しているかどうか、およびメジャー バージョン番号とマイナー バージョン番号が正しいかどうかが確認されます。直接のスーパークラスと見なされるクラスまたはインターフェースもすべてロードされます。これが完了すると、バイナリ表現からクラスまたはインターフェース オブジェクトが作成されます。

リンク: リンクには、クラスまたはインターフェースの検証、準備された型、クラスの直接の親クラスと親インターフェースが含まれます。つまり、リンクには検証、準備、解析(オプション)の3つのステップが含まれます。

検証: このフェーズでは、クラスとインターフェースの表現が構造的に正しく、Java プログラミング言語と JVM セマンティクスの要件を満たしていることを確認します。

検証段階でこれらのチェックを実行すると、実行時のリンク段階でこれらのアクションを回避できますが、クラスの読み込みが遅くなりますが、バイトコードの実行時にこれらのチェックが実行されなくなります。

準備: これには、静的ストレージと JVM によって使用されるデータ構造 (メソッド テーブルなど) のメモリ割り当てが含まれます。静的フィールドはデフォルト値で作成され、インスタンス化されます。ただし、これらのタスクはインスタンス化フェーズ中に実行されるため、このフェーズではインスタンス化子またはコードは実行されません。

解析: オプションのフェーズです。このフェーズでは、参照されているクラスまたはインターフェースをロードして、シンボル参照が正しいかどうかを確認します。この時点でこれらのチェックが行われない場合、シンボリック参照の解決はバイトコード命令によって使用される直前まで延期されます。

クラスまたはインターフェースのインスタンス化メソッドの実行を含め、クラスまたはインターフェースをインスタンス化します。

JVM には、異なる役割を持つ複数のクラス ローダーが存在します。各クラス ローダーは、その親クラス ローダーに委任します (ルート クラス ローダーであるブートストラップ クラス ローダーを除く)。

ブートストラップ クラス ローダー: Java プログラムの実行中、Java 仮想マシンは Java クラスをロードする必要があり、このプロセスを完了するにはクラス ローダーが必要です。クラスローダー自体も Java クラスであるため、人類の最初の母親がどのように生まれたのかという疑問と同様の疑問が生じます。

実際、Java 仮想マシンには Bootstrap と呼ばれるクラス ローダーが組み込まれており、これはオペレーティング システム固有のネイティブ コードで実装され、Java 仮想マシンのカーネルに属します。この Bootstrap クラス ローダーをロードするには、特別なクラス ローダーは必要ありません。 Bootstrap クラス ローダーは、Java コア パッケージ内のクラスをロードする役割を担います。

拡張クラス ローダー: 標準の Java 拡張 API からクラスをロードします。たとえば、セキュリティのための拡張機能セットなどです。

システム クラス ローダー: これはアプリケーションのデフォルトのクラス ローダーです。クラスパスからアプリケーション クラスを読み込みます。

ユーザー定義のクラスローダー: アプリケーションクラスをロードするためのクラスローダーを追加で定義できます。ユーザー定義のクラス ローダーは、実行時にクラスを再ロードしたり、一部の特殊なクラスを複数の異なるグループに分離したりするなどの特殊なシナリオで使用できます (通常、Tomcat などの Web サーバーではこのような要件があります)。

より高速なクラス読み込み

HotspotJVM 5.0 では、クラス データ共有 (CDS) と呼ばれる機能が導入されました。 JVM のインストール中に、インストーラーは共有アーカイブ用にマップされたメモリ領域に Java コア クラスのセット (rt.jar など) をロードします。 CDS はこれらのクラスのロード時間を短縮し、JVM の起動速度を向上させるとともに、これらのクラスを異なる JVM インスタンス間で共有できるようにします。これにより、メモリの断片化が大幅に減少します。

メソッドエリアの場所

JVM 仕様 Java SE 7 エディションでは、次のように明確に述べられています。メソッド領域はヒープ内の論理的な一部ですが、最も単純な実装は、ガベージ コレクションも圧縮も行わないことです。しかし、矛盾は、jconsole を使用して Oracle の JVM メソッド領域 (および CodeCache) を表示すると、非ヒープ形式になることです。 OpenJDK コードは、CodeCache が ObjectHeap に対して VM 内の独立したドメインであることを示しています。

クラスローダー参照

クラスは通常、オンデマンドでロードされます。つまり、クラスが初めて使用されるときにロードされます。クラスローダーのおかげで、Java ランタイムシステムはファイルとファイルシステムについて知る必要がありません。

ランタイム定数プール

JVM は各タイプに対して定数プールを維持します。これはシンボル テーブルに似たランタイム データ構造ですが、より多くのデータが含まれています。 Java バイトコードには、バイトコードに直接保存するには通常は大きすぎるデータが必要です。代わりに、定数プールに格納し、バイトコードに定数プールへの参照を含めるという方法もあります。ランタイム定数プールは主に動的リンクに使用されます。

定数プールには、次のようないくつかの種類のデータが格納されます。

  • 数値リテラル
  • 文字列リテラル
  • クラス参照
  • フィールド参照
  • メソッドリファレンス

次の単純なクラスをコンパイルすると:

  1. パッケージ org.jvminternals;パブリッククラス SimpleClass { public void sayHello() {System. .println ( "こんにちは" );}}

生成されたクラス ファイルの定数プールは次の図のようになります。

  1. 絶え間ない
  2. プール: #1 = Methodref #6.#17 // java/lang/Object. "<init>" :()V#2 =
  3. フィールド参照 #18.#19 // java/lang/System.出力:Ljava/io/PrintStream;#3 =
  4. 文字列 #20 // "Hello" #4 = メソッド参照 #21.#22 //
  5. java/io/PrintStream.println:(Ljava/lang/String;)V#5 = クラス #23 //
  6. org/jvminternals/SimpleClass#6 = クラス #24 // java/lang/Object#7 = Utf8
  7. <init> #8 = Utf8 ()V #9 = Utf8 コード #10 = Utf8 行番号テーブル #11
  8. = Utf8 ローカル変数テーブル #12 = Utf8 this #13 = Utf8
  9. Lorg/jvminternals/SimpleClass; #14 = Utf8 sayHello #15 = Utf8 ソースファイル
  10. #16 = Utf8 SimpleClass.java #17 = NameAndType #7:#8 //
  11. "<init>" :()V#18 = クラス #25 // java/lang/System#19 = NameAndType
  12. #26:#27 //出力:Ljava/io/PrintStream;#20 = Utf8 Hello #21 = クラス #28 //
  13. java/io/PrintStream#22 = 名前とタイプ #29:#30 //
  14. println:(Ljava/lang/String;)V#23 = Utf8 org/jvminternals/SimpleClass #24
  15. = Utf8 java/lang/Object#25 = Utf8 java/lang/System #26 = Utf8出力#27 =
  16. Utf8 Ljava/io/PrintStream; #28 = Utf8 java/io/PrintStream #29 = Utf8
  17. println #30 = Utf8 (Ljava/lang/String;)V

定数プールには次のタイプが含まれます。

例外テーブル

例外テーブルには、各例外ハンドラに関する情報が格納されます。

  • 出発点
  • 終点
  • 処理コードPCオフセット
  • キャッチされた例外クラスの定数プールインデックス

メソッドが try-catch または try-finally 例外ハンドラーを定義すると、例外テーブルが作成されます。これには、処理される例外の種類とハンドラー コードの場所とともに、各例外ハンドラーまたは finally ブロックに関する情報が含まれます。

例外がスローされると、JVM は現在のメソッドに一致するハンドラーを探します。見つからない場合、メソッドは最終的に現在のスタックフレームを突然ポップし、例外が呼び出しチェーン (新しいフレーム) に再スローされます。すべてのフレームがスタックからポップされる前に例外ハンドラが見つからない場合、現在のスレッドは終了します。もちろん、メイン スレッドなどの最後の非バックグラウンド スレッドで例外がスローされた場合、JVM が終了する可能性もあります。

最終的な例外ハンドラはすべての例外タイプに一致し、そのタイプの例外がスローされるたびに常に実行されます。例外がスローされない場合でも、メソッドの最後に finally ブロックが実行されます。 return ステートメントが実行されると、すぐに finally コード ブロックにジャンプして実行を続行します。

キャラクター比較

文字比較とは、辞書の順序で単一の文字または文字列のサイズを比較する操作を指します。一般的に、文字の比較の基準として ASCII コード値のサイズが使用されます。

シンボルテーブル

コンパイルプロセス中、シンボルテーブルは、ソースプログラム内の一部の文法シンボルの種類や特性などの関連情報を継続的に収集、記録、使用する必要があります。この情報は通常、表形式でシステムに保存されます。定数テーブル、変数名テーブル、配列名テーブル、手続き名テーブル、ラベルテーブルなどを総称してシンボルテーブルと呼びます。シンボルテーブルの構成、構築、管理方法の品質は、コンパイルシステムの動作効率に直接影響します。

JVM では、内部文字列は文字列テーブルに保存されます。文字列テーブルは、オブジェクト ポインターをシンボルにマッピングするハッシュ テーブルです (例:

文字列リテラルはコンパイラによって自動的に「内部化」され、クラスがロードされるときに文字列テーブルに追加されます。さらに、String.intern() を呼び出すことによって、文字列クラスのインスタンスを明示的に内部化できます。 String.intern() が呼び出されたときに、シンボル テーブルにすでに文字列が含まれている場合は、その文字列への参照が返されます。文字列が文字列テーブルに含まれていない場合は、文字列テーブルに追加され、その参照が返されます。

<<:  企業はクラウドの透明性を高める必要がある

>>:  オラクル、従業員2,000人増員、クラウド事業を積極展開へ

推薦する

立ち上げから2か月後の新サイトの最適化体験

新しいウェブサイトを最適化するのは簡単ではないと言われていますが、実際に経験してみなければ、どこに難...

クルンはどうですか? 「Three Elite Networks」シリーズのサーバーについての簡単なレビュー

クルンはどうですか?クルンサーバーはどうですか? Kurunは国内IDC市場では比較的有名で、主に米...

gcoreはどうですか? gcore 香港 VPS 評価データ共有

gcoreはどうですか? gcore香港はどうですか? gcore は、中国香港で香港 VPS、香港...

クラウドコンピューティングの未来は完全なハイブリッドクラウドです

クラウド コンピューティングの将来はかなり厳しい競争に直面しており、IDG Research Ser...

ウェブサイト上でユーザーに「追いつく」3段階の習慣テストは、ユーザーの考えを理解するのに役立ちます

Nir Eyal (TechCrunch) 著過去 25 年間の真に優れた消費者向けテクノロジー企業...

モバイル向けに最適化されたウェブサイトに関する Google の推奨事項

近年のスマートフォンの普及により、モバイルデバイス経由でウェブサイトを閲覧するユーザーが増えており、...

ウェブサイトのセキュリティはウェブマスターの最優先事項です

2 日前、私の Web サイトがハッキングされました。バックエンド ディレクトリ フォルダーに PH...

Baidu は小規模なトラフィックのオンライン ICO アイコンを推進

Baidu が有名なウェブサイトをいくつか含める場合、そのウェブサイトの形式と権威を示すために、Ba...

「SAP自閉症人材就職準備スキルスクール」プロジェクトが正式に開始されました

本日、「SAP 自閉症人材就職準備スキルスクール」プロジェクトが正式に開始され、社会に出て就職の準備...

モノのインターネットの爆発的な普及により、エッジコンピューティングの進歩が求められている。

調査会社IDCによると、モノのインターネット(IoT)への支出は2020年までに1.3兆ドルに達し、...

病院でブランドサービスマーケティングを成功させる方法

現在、どの都市にもさまざまな規模の病院があり、ユーザーには多くの選択肢があります。この点だけから見て...

SalesEasy CRM: 次の段階で、中国の SaaS 企業はどのようにして繭から抜け出し、スケーラブルな成長を達成できるのでしょうか?

6月10日、国内のSaaS企業、投資機関、メディアからのゲスト5名( Salesfunnel創業者...

インターネット企業の急速な興亡の全過程

インターネット企業の急速な興亡の全過程については、「MySpace を盗んだのは誰か: ソーシャル ...

ウェブサイトはスタートラインで勝利する:記事タイトルの最適化は非常に重要です

記事のタイトルは魅力的なコートに相当します。美しい服を着ている人は、いつも他の人の注目を集めることが...